mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
ide: Skylark support, Skylark: tutorial
git-svn-id: svn://ultimatepp.org/upp/trunk@5188 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
bd1509651b
commit
0968b272e2
17 changed files with 1494 additions and 1054 deletions
|
|
@ -401,7 +401,7 @@ void CodeEditor::InitKeywords()
|
|||
"CLASSNAME", "THISBACK", "THISBACK1", "THISBACK2", "THISBACK3", "THISBACK4",
|
||||
"PTEBACK", "PTEBACK1", "PTEBACK2", "PTEBACK3", "PTEBACK4",
|
||||
"QUOTE", "XASSERT", "NEVER", "XNEVER", "CHECK", "XCHECK", "ASSERT",
|
||||
"NAMESPACE_UPP", "END_UPP_NAMESPACE", "NEVER_",
|
||||
"NAMESPACE_UPP", "END_UPP_NAMESPACE", "NEVER_", "SKYLARK",
|
||||
NULL
|
||||
};
|
||||
static const char *upp_logs[] = {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,14 @@ void SetIniFile(const char *name) {
|
|||
ReloadIniFile();
|
||||
}
|
||||
|
||||
static
|
||||
void sIniSet(int64& version)
|
||||
{
|
||||
version = s_ini_version;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
bool sIniChanged(int64& version)
|
||||
{
|
||||
if(version != s_ini_version) {
|
||||
|
|
@ -119,6 +126,7 @@ String IniString::operator=(const String& s)
|
|||
{
|
||||
Mutex::Lock __(sMtx);
|
||||
(*ref_fn)() = s;
|
||||
sIniSet(version);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +179,7 @@ IniInt::operator int() {
|
|||
|
||||
int IniInt::operator=(int b) {
|
||||
Mutex::Lock __(sMtx);
|
||||
sIniSet(version);
|
||||
return value = b;
|
||||
}
|
||||
|
||||
|
|
@ -193,6 +202,7 @@ IniInt64::operator int64()
|
|||
int64 IniInt64::operator=(int64 b)
|
||||
{
|
||||
Mutex::Lock __(sMtx);
|
||||
sIniSet(version);
|
||||
return value = b;
|
||||
}
|
||||
|
||||
|
|
@ -215,6 +225,7 @@ IniDouble::operator double()
|
|||
double IniDouble::operator=(double b)
|
||||
{
|
||||
Mutex::Lock __(sMtx);
|
||||
sIniSet(version);
|
||||
return value = b;
|
||||
}
|
||||
|
||||
|
|
@ -237,6 +248,7 @@ IniBool::operator bool() {
|
|||
|
||||
bool IniBool::operator=(bool b) {
|
||||
Mutex::Lock __(sMtx);
|
||||
sIniSet(version);
|
||||
return value = b;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ String AsJSON(const Value& v, const String& sep, bool pretty)
|
|||
if(IsNumber(v))
|
||||
return Format("%.16g", (double)v);
|
||||
if(IsString(v))
|
||||
return AsCString((String)v, INT_MAX, NULL, ASCSTRING_OCTALHI|ASCSTRING_JSON);
|
||||
return AsCString((String)v, INT_MAX, NULL, ASCSTRING_JSON);
|
||||
if(IsNull(v))
|
||||
return "null";
|
||||
#ifdef SVO_VALUE
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ Value ParseJSON(const char *s);
|
|||
inline String AsJSON(int i) { return IsNull(i) ? "null" : AsString(i); }
|
||||
inline String AsJSON(double n) { return IsNull(n) ? "null" : AsString(n); }
|
||||
inline String AsJSON(bool b) { return b ? "true" : "false"; }
|
||||
inline String AsJSON(const String& s) { return AsCString(s, INT_MAX, NULL, ASCSTRING_OCTALHI|ASCSTRING_JSON); }
|
||||
inline String AsJSON(const WString& s) { return AsCString(s.ToString(), INT_MAX, NULL, ASCSTRING_OCTALHI|ASCSTRING_JSON); }
|
||||
inline String AsJSON(const char *s) { return AsCString(s, INT_MAX, NULL, ASCSTRING_OCTALHI|ASCSTRING_JSON); }
|
||||
inline String AsJSON(const String& s) { return AsCString(s, INT_MAX, NULL, ASCSTRING_JSON); }
|
||||
inline String AsJSON(const WString& s) { return AsCString(s.ToString(), INT_MAX, NULL, ASCSTRING_JSON); }
|
||||
inline String AsJSON(const char *s) { return AsCString(s, INT_MAX, NULL, ASCSTRING_JSON); }
|
||||
|
||||
String AsJSON(const Value& v, const String& indent, bool pretty);
|
||||
String AsJSON(const Value& v, bool pretty = false);
|
||||
|
|
|
|||
|
|
@ -668,6 +668,21 @@ Array<Parser::Decl> Parser::Declaration0(bool l0, bool more)
|
|||
break;
|
||||
}
|
||||
Qualifier();
|
||||
if(l0 && lex == tk_SKYLARK && lex[1] == '(') {
|
||||
++lex;
|
||||
++lex;
|
||||
Decl& a = r.Add();
|
||||
a.name = lex.GetId();
|
||||
a.function = true;
|
||||
Decl& p = a.param.Add();
|
||||
p.name = "http";
|
||||
p.type = "Http";
|
||||
p.natural = "Http& http";
|
||||
Key(',');
|
||||
lex.GetText();
|
||||
Key(')');
|
||||
return r;
|
||||
}
|
||||
bool isdestructor = Key('~');
|
||||
if(l0 && context.typenames.Find(lex) >= 0 && lex[1] == '(' && lex.IsId()) {
|
||||
Decl& a = r.Add();
|
||||
|
|
|
|||
|
|
@ -79,3 +79,5 @@ CPPID(for)
|
|||
CPPID(try)
|
||||
CPPID(catch)
|
||||
CPPID(do)
|
||||
|
||||
CPPID(SKYLARK)
|
||||
|
|
|
|||
|
|
@ -1,296 +1,300 @@
|
|||
#include "Skylark.h"
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
#include <wincon.h>
|
||||
#endif
|
||||
|
||||
namespace Upp {
|
||||
|
||||
String GetThreadName()
|
||||
{
|
||||
return FormatIntBase(Thread::GetCurrentId() % 33, 35);
|
||||
}
|
||||
|
||||
namespace Ini {
|
||||
INI_BOOL(skylark_log, false, "Trace of Skylark");
|
||||
};
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
BOOL WINAPI SkylarkApp::CtrlCHandlerRoutine(__in DWORD dwCtrlType)
|
||||
{
|
||||
LOG("Ctrl+C handler");
|
||||
TheApp().quit = true;
|
||||
Cout() << "Ctrl + C\n";
|
||||
TcpSocket h;
|
||||
h.Connect("127.0.0.1", TheApp().port);
|
||||
h.Put("quit");
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SkylarkApp::WorkThread()
|
||||
{
|
||||
RunThread();
|
||||
}
|
||||
|
||||
void SkylarkApp::ThreadRun()
|
||||
{
|
||||
WorkThread();
|
||||
}
|
||||
|
||||
void SkylarkApp::RunThread()
|
||||
{
|
||||
if(SQL.IsOpen()) {
|
||||
SQL.ClearError();
|
||||
SQLR.ClearError();
|
||||
SQL.GetSession().ThrowOnError();
|
||||
SQLR.GetSession().ThrowOnError();
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
TcpSocket request;
|
||||
accept_mutex.Enter();
|
||||
if(quit) {
|
||||
accept_mutex.Leave();
|
||||
break;
|
||||
}
|
||||
SKYLARKLOG("Waiting for accept ");
|
||||
bool b = request.Accept(server);
|
||||
accept_mutex.Leave();
|
||||
if(quit)
|
||||
break;
|
||||
if(b) {
|
||||
SKYLARKLOG("Accepted ");
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(prefork)
|
||||
alarm(timeout);
|
||||
#endif
|
||||
Http http(*this);
|
||||
http.Dispatch(request);
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(prefork)
|
||||
alarm(0);
|
||||
#endif
|
||||
SKYLARKLOG("Finished ");
|
||||
}
|
||||
else {
|
||||
SKYLARKLOG("Accept failed: " << request.GetErrorDesc());
|
||||
#ifdef _DEBUG
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkylarkApp::Main()
|
||||
{
|
||||
Buffer<Thread> uwt(threads);
|
||||
for(int i = 0; i < threads; i++)
|
||||
Thread::Start(THISBACK(ThreadRun));
|
||||
|
||||
while(Thread::GetCount())
|
||||
Sleep(100);
|
||||
}
|
||||
|
||||
void SkylarkApp::Broadcast(int signal)
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(getpid() == main_pid)
|
||||
for(int i = 0; i < child_pid.GetCount(); i++)
|
||||
kill(child_pid[i], signal);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkylarkApp::Signal(int signal)
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
switch(signal) {
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
quit = true;
|
||||
Broadcast(signal);
|
||||
break;
|
||||
case SIGINT:
|
||||
Broadcast(signal);
|
||||
exit(0);
|
||||
break;
|
||||
case SIGALRM:
|
||||
if(getpid() != TheApp().main_pid) {
|
||||
// "Timeout - session stoped"
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkylarkApp::SignalHandler(int signal)
|
||||
{
|
||||
TheApp().Signal(signal);
|
||||
}
|
||||
|
||||
void DisableHUP()
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGHUP);
|
||||
sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EnableHUP()
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGHUP);
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkylarkApp::Run()
|
||||
{
|
||||
// DisableHUP();
|
||||
if(static_dir.GetCount() == 0)
|
||||
static_dir = root + "/static";
|
||||
|
||||
SqlSession::PerThread();
|
||||
SqlId::UseQuotes();
|
||||
FinalizeViews();
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
SetConsoleCtrlHandler(CtrlCHandlerRoutine, true);
|
||||
#endif
|
||||
|
||||
main_pid = getpid();
|
||||
quit = false;
|
||||
|
||||
#if defined(PLATFORM_POSIX) && defined(_DEBUG)
|
||||
// Avoid the need to close running server in debug mode...
|
||||
int qq = 0;
|
||||
for(;;) {
|
||||
if(server.Listen(port, 5))
|
||||
break;
|
||||
Cout() << "Trying to start listening (other process using the same port?) " << ++qq << "\n";
|
||||
Sleep(1000);
|
||||
}
|
||||
#else
|
||||
if(!server.Listen(port, 5)) {
|
||||
SKYLARKLOG("Cannot open server socket!");
|
||||
Exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
SKYLARKLOG("Starting Skylark, current static path: " << path);
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(prefork) {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = SignalHandler;
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
sigaction(SIGALRM, &sa, NULL);
|
||||
// EnableHUP();
|
||||
while(!quit) {
|
||||
while(child_pid.GetCount() < prefork && !quit) {
|
||||
pid_t p = fork();
|
||||
if(p == 0) {
|
||||
Main();
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(p > 0)
|
||||
child_pid.Add(p);
|
||||
else {
|
||||
// "cant create new process"
|
||||
Broadcast(SIGINT);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
int status = 0;
|
||||
pid_t p = wait(&status);
|
||||
if(p > 0) {
|
||||
int q = FindIndex(child_pid, p);
|
||||
if(q >= 0)
|
||||
child_pid.Remove(q);
|
||||
}
|
||||
}
|
||||
|
||||
Broadcast(SIGTERM);
|
||||
int status = 0;
|
||||
for(int i = 0; i < child_pid.GetCount(); i++)
|
||||
waitpid(child_pid[i], &status, 0);
|
||||
// "server stopped";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
Main();
|
||||
|
||||
#if defined(_DEBUG) && defined(POSIX)
|
||||
FileDelete(pidf);
|
||||
#endif
|
||||
|
||||
SKYLARKLOG("ExitSkylark");
|
||||
}
|
||||
|
||||
|
||||
void SkylarkApp::SqlError(Http& http)
|
||||
{
|
||||
}
|
||||
|
||||
void SkylarkApp::InternalError(Http& http)
|
||||
{
|
||||
}
|
||||
|
||||
void SkylarkApp::NotFound(Http& http)
|
||||
{
|
||||
}
|
||||
|
||||
void SkylarkApp::Unauthorized(Http& http)
|
||||
{
|
||||
}
|
||||
|
||||
SkylarkApp *SkylarkApp::app;
|
||||
|
||||
SkylarkApp& SkylarkApp::TheApp()
|
||||
{
|
||||
ASSERT(app);
|
||||
return *app;
|
||||
}
|
||||
|
||||
const SkylarkConfig& SkylarkApp::Config()
|
||||
{
|
||||
ASSERT(app);
|
||||
return *app;
|
||||
}
|
||||
|
||||
SkylarkApp::SkylarkApp()
|
||||
{
|
||||
ASSERT(!app);
|
||||
path = GetEnv("UPP_ASSEMBLY__");
|
||||
app = this;
|
||||
threads = 3 * CPU_Cores() + 1;
|
||||
port = 8001;
|
||||
use_caching = true;
|
||||
#ifdef _DEBUG
|
||||
prefork = 0;
|
||||
timeout = 0;
|
||||
#else
|
||||
prefork = 1;
|
||||
timeout = 300;
|
||||
#endif
|
||||
}
|
||||
|
||||
SkylarkApp::~SkylarkApp()
|
||||
{
|
||||
app = NULL;
|
||||
}
|
||||
|
||||
#include "Skylark.h"
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
#include <wincon.h>
|
||||
#endif
|
||||
|
||||
namespace Upp {
|
||||
|
||||
String GetThreadName()
|
||||
{
|
||||
return FormatIntBase(Thread::GetCurrentId() % 33, 35);
|
||||
}
|
||||
|
||||
namespace Ini {
|
||||
INI_BOOL(skylark_log, false, "Trace of Skylark");
|
||||
};
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
BOOL WINAPI SkylarkApp::CtrlCHandlerRoutine(__in DWORD dwCtrlType)
|
||||
{
|
||||
LOG("Ctrl+C handler");
|
||||
TheApp().quit = true;
|
||||
Cout() << "Ctrl + C\n";
|
||||
TcpSocket h;
|
||||
h.Connect("127.0.0.1", TheApp().port);
|
||||
h.Put("quit");
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SkylarkApp::WorkThread()
|
||||
{
|
||||
RunThread();
|
||||
}
|
||||
|
||||
void SkylarkApp::ThreadRun()
|
||||
{
|
||||
WorkThread();
|
||||
}
|
||||
|
||||
void SkylarkApp::RunThread()
|
||||
{
|
||||
if(SQL.IsOpen()) {
|
||||
SQL.ClearError();
|
||||
SQLR.ClearError();
|
||||
SQL.GetSession().ThrowOnError();
|
||||
SQLR.GetSession().ThrowOnError();
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
TcpSocket request;
|
||||
accept_mutex.Enter();
|
||||
if(quit) {
|
||||
accept_mutex.Leave();
|
||||
break;
|
||||
}
|
||||
SKYLARKLOG("Waiting for accept ");
|
||||
bool b = request.Accept(server);
|
||||
accept_mutex.Leave();
|
||||
if(quit)
|
||||
break;
|
||||
if(b) {
|
||||
SKYLARKLOG("Accepted ");
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(prefork)
|
||||
alarm(timeout);
|
||||
#endif
|
||||
Http http(*this);
|
||||
http.Dispatch(request);
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(prefork)
|
||||
alarm(0);
|
||||
#endif
|
||||
SKYLARKLOG("Finished ");
|
||||
}
|
||||
else {
|
||||
SKYLARKLOG("Accept failed: " << request.GetErrorDesc());
|
||||
#ifdef _DEBUG
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkylarkApp::Main()
|
||||
{
|
||||
Buffer<Thread> uwt(threads);
|
||||
for(int i = 0; i < threads; i++)
|
||||
Thread::Start(THISBACK(ThreadRun));
|
||||
|
||||
while(Thread::GetCount())
|
||||
Sleep(100);
|
||||
}
|
||||
|
||||
void SkylarkApp::Broadcast(int signal)
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(getpid() == main_pid)
|
||||
for(int i = 0; i < child_pid.GetCount(); i++)
|
||||
kill(child_pid[i], signal);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkylarkApp::Signal(int signal)
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
switch(signal) {
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
quit = true;
|
||||
Broadcast(signal);
|
||||
break;
|
||||
case SIGINT:
|
||||
Broadcast(signal);
|
||||
exit(0);
|
||||
break;
|
||||
case SIGALRM:
|
||||
if(getpid() != TheApp().main_pid) {
|
||||
// "Timeout - session stoped"
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkylarkApp::SignalHandler(int signal)
|
||||
{
|
||||
TheApp().Signal(signal);
|
||||
}
|
||||
|
||||
void DisableHUP()
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGHUP);
|
||||
sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EnableHUP()
|
||||
{
|
||||
#ifdef PLATFORM_POSIX
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGHUP);
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkylarkApp::Run()
|
||||
{
|
||||
// DisableHUP();
|
||||
if(static_dir.GetCount() == 0)
|
||||
static_dir = root + "/static";
|
||||
|
||||
SqlSession::PerThread();
|
||||
SqlId::UseQuotes();
|
||||
FinalizeViews();
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
SetConsoleCtrlHandler(CtrlCHandlerRoutine, true);
|
||||
#endif
|
||||
|
||||
main_pid = getpid();
|
||||
quit = false;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Avoid the need to close running server in debug mode...
|
||||
int qq = 0;
|
||||
for(;;) {
|
||||
if(server.Listen(port, 5))
|
||||
break;
|
||||
Cout() << "Trying to start listening (other process using the same port?) " << ++qq << "\n";
|
||||
Sleep(1000);
|
||||
}
|
||||
#else
|
||||
if(!server.Listen(port, 5)) {
|
||||
SKYLARKLOG("Cannot open server socket!");
|
||||
Exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
SKYLARKLOG("Starting Skylark, current static path: " << path);
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
if(prefork) {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = SignalHandler;
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
sigaction(SIGALRM, &sa, NULL);
|
||||
// EnableHUP();
|
||||
while(!quit) {
|
||||
while(child_pid.GetCount() < prefork && !quit) {
|
||||
pid_t p = fork();
|
||||
if(p == 0) {
|
||||
Main();
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(p > 0)
|
||||
child_pid.Add(p);
|
||||
else {
|
||||
// "cant create new process"
|
||||
Broadcast(SIGINT);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
int status = 0;
|
||||
pid_t p = wait(&status);
|
||||
if(p > 0) {
|
||||
int q = FindIndex(child_pid, p);
|
||||
if(q >= 0)
|
||||
child_pid.Remove(q);
|
||||
}
|
||||
}
|
||||
|
||||
Broadcast(SIGTERM);
|
||||
int status = 0;
|
||||
for(int i = 0; i < child_pid.GetCount(); i++)
|
||||
waitpid(child_pid[i], &status, 0);
|
||||
// "server stopped";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
Main();
|
||||
|
||||
#if defined(_DEBUG) && defined(POSIX)
|
||||
FileDelete(pidf);
|
||||
#endif
|
||||
|
||||
SKYLARKLOG("ExitSkylark");
|
||||
}
|
||||
|
||||
|
||||
void SkylarkApp::SqlError(Http& http)
|
||||
{
|
||||
}
|
||||
|
||||
void SkylarkApp::InternalError(Http& http)
|
||||
{
|
||||
}
|
||||
|
||||
void SkylarkApp::NotFound(Http& http)
|
||||
{
|
||||
}
|
||||
|
||||
void SkylarkApp::Unauthorized(Http& http)
|
||||
{
|
||||
}
|
||||
|
||||
void SkylarkApp::BadRequest(Http& http)
|
||||
{
|
||||
}
|
||||
|
||||
SkylarkApp *SkylarkApp::app;
|
||||
|
||||
SkylarkApp& SkylarkApp::TheApp()
|
||||
{
|
||||
ASSERT(app);
|
||||
return *app;
|
||||
}
|
||||
|
||||
const SkylarkConfig& SkylarkApp::Config()
|
||||
{
|
||||
ASSERT(app);
|
||||
return *app;
|
||||
}
|
||||
|
||||
SkylarkApp::SkylarkApp()
|
||||
{
|
||||
ASSERT(!app);
|
||||
path = GetEnv("UPP_ASSEMBLY__");
|
||||
app = this;
|
||||
threads = 3 * CPU_Cores() + 1;
|
||||
port = 8001;
|
||||
use_caching = true;
|
||||
#ifdef _DEBUG
|
||||
prefork = 0;
|
||||
timeout = 0;
|
||||
#else
|
||||
prefork = 1;
|
||||
timeout = 300;
|
||||
#endif
|
||||
}
|
||||
|
||||
SkylarkApp::~SkylarkApp()
|
||||
{
|
||||
app = NULL;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,394 +1,402 @@
|
|||
#include "Skylark.h"
|
||||
|
||||
#define LLOG(x) //DLOG(x)
|
||||
#define LDUMP(x) //DDUMP(x)
|
||||
#define LDUMPC(x) //DDUMPC(x)
|
||||
#define LDUMPM(x) //DDUMPM(x)
|
||||
#define LTIMING(x) //RTIMING(x)
|
||||
|
||||
namespace Upp {
|
||||
|
||||
enum { DISPATCH_VARARGS = -1 };
|
||||
|
||||
struct DispatchNode : Moveable<DispatchNode> {
|
||||
VectorMap<String, int> subnode;
|
||||
void (*view)(Http&);
|
||||
int argpos;
|
||||
int method;
|
||||
bool post_raw;
|
||||
String id;
|
||||
|
||||
enum { GET, POST };
|
||||
|
||||
DispatchNode() { view = NULL; argpos = Null; method = GET; post_raw = false; }
|
||||
};
|
||||
|
||||
static Vector<DispatchNode>& sDispatchMap()
|
||||
{
|
||||
static Vector<DispatchNode> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static VectorMap<String, Vector<String> >& sLinkMap()
|
||||
{
|
||||
static VectorMap<String, Vector<String> > x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static Index<uintptr_t>& sViewIndex()
|
||||
{
|
||||
static Index<uintptr_t> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void DumpDispatchMap()
|
||||
{
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
for(int i = 0; i < DispatchMap.GetCount(); i++) {
|
||||
LLOG("-------------");
|
||||
String sub;
|
||||
for(int j = 0; j < DispatchMap[i].subnode.GetCount(); j++)
|
||||
sub << DispatchMap[i].subnode.GetKey(j) << "->" << DispatchMap[i].subnode[j] << ", ";
|
||||
LLOG(i << " " << (bool)DispatchMap[i].view << ": " << sub);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> *GetUrlViewLinkParts(const String& id)
|
||||
{
|
||||
int q = sLinkMap().Find(id);
|
||||
if(q < 0)
|
||||
return NULL;
|
||||
return &sLinkMap()[q];
|
||||
}
|
||||
|
||||
String MakeLink(void (*view)(Http&), const Vector<Value>& arg)
|
||||
{
|
||||
int q = sViewIndex().Find((uintptr_t)view);
|
||||
if(q < 0)
|
||||
throw Exc("Invalid view");
|
||||
if(q < 0)
|
||||
return String();
|
||||
StringBuffer out;
|
||||
MakeLink(out, sLinkMap()[q], arg);
|
||||
return out;
|
||||
}
|
||||
|
||||
void RegisterView0(void (*view)(Http&), const char *id, String path, bool primary)
|
||||
{
|
||||
LLOG("RegisterView " << path);
|
||||
Vector<String>& linkpart = sLinkMap().GetAdd(id);
|
||||
sViewIndex().FindAdd((uintptr_t)view);
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
int method = DispatchNode::GET;
|
||||
bool post_raw = false;
|
||||
int q = path.Find(':');
|
||||
if(q >= 0) {
|
||||
if(path.Mid(q + 1) == "POST")
|
||||
method = DispatchNode::POST;
|
||||
if(path.Mid(q + 1) == "POST_RAW") {
|
||||
method = DispatchNode::POST;
|
||||
post_raw = true;
|
||||
}
|
||||
path = path.Mid(0, q);
|
||||
}
|
||||
Vector<String> h = Split(path, '/');
|
||||
if(DispatchMap.GetCount() == 0)
|
||||
DispatchMap.Add();
|
||||
q = 0;
|
||||
int linkargpos = 0;
|
||||
for(int i = 0; i < h.GetCount(); i++) {
|
||||
String s = h[i];
|
||||
LLOG(" Node " << h[i]);
|
||||
DispatchNode& n = DispatchMap[q];
|
||||
if(*s == '*') {
|
||||
int argpos = Null;
|
||||
if(IsDigit(s[1]))
|
||||
linkargpos = argpos = minmax(atoi(~s + 1), 0, 30);
|
||||
else
|
||||
if(s[1] == '*')
|
||||
argpos = DISPATCH_VARARGS;
|
||||
q = DispatchMap.GetCount();
|
||||
LLOG(" Adding arg " << argpos << ": " << q);
|
||||
n.subnode.Add(Null, q);
|
||||
DispatchMap.Add();
|
||||
DispatchMap[q].argpos = argpos;
|
||||
if(primary)
|
||||
linkpart.Add(String(linkargpos++, 1));
|
||||
}
|
||||
else {
|
||||
if(primary)
|
||||
linkpart.Add(s);
|
||||
q = n.subnode.Get(s, -1);
|
||||
if(q < 0) {
|
||||
q = DispatchMap.GetCount();
|
||||
LLOG(" Adding " << s << ": " << q);
|
||||
n.subnode.Add(s, q);
|
||||
DispatchMap.Add();
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_(!DispatchMap[q].view, "duplicate view " + String(path));
|
||||
DispatchMap[q].view = view;
|
||||
DispatchMap[q].method = method;
|
||||
DispatchMap[q].id = id;
|
||||
DispatchMap[q].post_raw = post_raw;
|
||||
// DumpDispatchMap();
|
||||
}
|
||||
|
||||
struct ViewData {
|
||||
void (*view)(Http&);
|
||||
String id;
|
||||
String path;
|
||||
};
|
||||
|
||||
static Array<ViewData>& sViewData()
|
||||
{
|
||||
static Array<ViewData> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void RegisterView(void (*view)(Http&), const char *id, const char *path)
|
||||
{
|
||||
Array<ViewData>& v = sViewData();
|
||||
ViewData& w = v.Add();
|
||||
w.view = view;
|
||||
w.id = id;
|
||||
w.path = path;
|
||||
}
|
||||
|
||||
void SkylarkApp::FinalizeViews()
|
||||
{
|
||||
Array<ViewData>& w = sViewData();
|
||||
for(int i = 0; i < w.GetCount(); i++) {
|
||||
const ViewData& v = w[i];
|
||||
ASSERT_(sViewIndex().Find((uintptr_t)v.view) < 0, "duplicate view function registration " + String(v.id));
|
||||
Vector<String> h = Split(ReplaceVars(root + '/' + v.path, view_var, '$'), ';');
|
||||
for(int i = 0; i < h.GetCount(); i++)
|
||||
RegisterView0(v.view, v.id, h[i], i == 0);
|
||||
}
|
||||
w.Clear();
|
||||
}
|
||||
|
||||
struct BestDispatch {
|
||||
void (*view)(Http&);
|
||||
int matched_parts;
|
||||
int matched_params;
|
||||
Vector<String>& arg;
|
||||
String id;
|
||||
bool post_raw;
|
||||
|
||||
BestDispatch(Vector<String>& arg) : arg(arg) { matched_parts = -1; matched_params = 0; view = NULL; post_raw = false; }
|
||||
};
|
||||
|
||||
void GetBestDispatch(int method,
|
||||
const Vector<String>& part, int ii, const DispatchNode& n, Vector<String>& arg,
|
||||
BestDispatch& bd, int matched_parts, int matched_params)
|
||||
{
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
if(ii >= part.GetCount()) {
|
||||
if(n.view && n.method == method &&
|
||||
(matched_parts > bd.matched_parts ||
|
||||
matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
|
||||
LLOG("Matched " << n.id << " parts " << matched_parts << " params " << matched_params);
|
||||
bd.arg <<= arg;
|
||||
bd.view = n.view;
|
||||
bd.matched_parts = matched_parts;
|
||||
bd.id = n.id;
|
||||
bd.post_raw = n.post_raw;
|
||||
}
|
||||
if(!bd.view) {
|
||||
int q = n.subnode.Find(String());
|
||||
while(q >= 0) {
|
||||
const DispatchNode& an = DispatchMap[n.subnode[q]];
|
||||
if(an.argpos == DISPATCH_VARARGS && an.view && an.method == method) {
|
||||
bd.view = an.view;
|
||||
bd.id = n.id;
|
||||
bd.arg.Clear();
|
||||
break;
|
||||
}
|
||||
q = n.subnode.FindNext(q);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
int qq = n.subnode.Get(part[ii], -1);
|
||||
if(qq >= 0)
|
||||
GetBestDispatch(method, part, ii + 1, DispatchMap[qq], arg, bd, matched_parts + 1, matched_params);
|
||||
int q = n.subnode.Find(String());
|
||||
while(q >= 0) {
|
||||
int qq = n.subnode[q];
|
||||
int ac = arg.GetCount();
|
||||
const DispatchNode& an = DispatchMap[qq];
|
||||
int apos = an.argpos;
|
||||
LLOG(" *" << qq << " apos: " << apos);
|
||||
if(apos == DISPATCH_VARARGS) {
|
||||
if(an.view && an.method == method &&
|
||||
(matched_parts > bd.matched_parts || matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
|
||||
LLOG("Matched VARARGS " << an.id << " parts " << matched_parts << " params " << matched_params);
|
||||
bd.arg <<= arg;
|
||||
bd.arg.Append(part, ii, part.GetCount() - ii);
|
||||
bd.view = an.view;
|
||||
bd.matched_parts = matched_parts;
|
||||
bd.id = an.id;
|
||||
}
|
||||
}
|
||||
else {
|
||||
String pv;
|
||||
if(IsNull(apos))
|
||||
arg.Add(part[ii]);
|
||||
else {
|
||||
String& at = arg.At(apos);
|
||||
pv = at;
|
||||
at = part[ii];
|
||||
}
|
||||
GetBestDispatch(method, part, ii + 1, an, arg, bd, matched_parts, matched_params + 1);
|
||||
if(!IsNull(apos))
|
||||
arg[apos] = pv;
|
||||
}
|
||||
arg.SetCount(ac);
|
||||
q = n.subnode.FindNext(q);
|
||||
}
|
||||
}
|
||||
|
||||
void Http::Dispatch(TcpSocket& socket)
|
||||
{
|
||||
const Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
if(hdr.Read(socket)) {
|
||||
int len = GetLength();
|
||||
content = socket.GetAll(len);
|
||||
LLOG("--------------------------------------------");
|
||||
SKYLARKLOG(hdr.GetMethod() << " " << hdr.GetURI());
|
||||
LDUMP(content);
|
||||
String r;
|
||||
var.Clear();
|
||||
arg.Clear();
|
||||
LTIMING("Request processing");
|
||||
request_content_type = GetHeader("content-type");
|
||||
String rc = ToLower(request_content_type);
|
||||
bool post = hdr.GetMethod() == "POST";
|
||||
if(post)
|
||||
if(rc.StartsWith("application/x-www-form-urlencoded"))
|
||||
ParseRequest(content);
|
||||
else
|
||||
if(rc.StartsWith("multipart/"))
|
||||
ReadMultiPart(content);
|
||||
String uri = hdr.GetURI();
|
||||
int q = uri.Find('?');
|
||||
if(q >= 0) {
|
||||
if(!post)
|
||||
ParseRequest(~uri + q + 1);
|
||||
uri.Trim(q);
|
||||
}
|
||||
for(int i = hdr.fields.Find("cookie"); i >= 0; i = hdr.fields.FindNext(i)) {
|
||||
const String& h = hdr.fields[i];
|
||||
int q = 0;
|
||||
for(;;) {
|
||||
int qq = h.Find('=', q);
|
||||
if(qq < 0)
|
||||
break;
|
||||
String id = ToLower(TrimBoth(h.Mid(q, qq - q)));
|
||||
qq++;
|
||||
q = h.Find(';', qq);
|
||||
if(q < 0) {
|
||||
var.Add('@' + id, UrlDecode(h.Mid(qq)));
|
||||
break;
|
||||
}
|
||||
var.Add('@' + id, UrlDecode(h.Mid(qq, q - qq)));
|
||||
q++;
|
||||
}
|
||||
}
|
||||
var.GetAdd("static") = app.static_dir;
|
||||
var.GetAdd(".__identity__"); // To make StdLib.icpp GetIndentity work without changing preset stack positions
|
||||
LDUMPM(var);
|
||||
Vector<String> part = Split(uri, '/');
|
||||
for(int i = 0; i < part.GetCount(); i++)
|
||||
part[i] = UrlDecode(part[i]);
|
||||
LDUMPC(part);
|
||||
Vector<String> a;
|
||||
BestDispatch bd(arg);
|
||||
if(DispatchMap.GetCount())
|
||||
GetBestDispatch(post ? DispatchNode::POST : DispatchNode::GET, part, 0, DispatchMap[0], a, bd, 0, 0);
|
||||
LDUMPC(arg);
|
||||
response.Clear();
|
||||
if(bd.view) {
|
||||
try {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Begin();
|
||||
LoadSession();
|
||||
session_dirty = false;
|
||||
if(post && !bd.post_raw) {
|
||||
String id = Nvl((*this)["__post_identity__"], (*this)["__js_identity__"]);
|
||||
if(id != (*this)[".__identity__"])
|
||||
throw AuthExc("identity error");
|
||||
}
|
||||
lang = Nvl(Int(".__lang__"), LNG_ENGLISH);
|
||||
Upp::SetLanguage(lang);
|
||||
var.GetAdd(".__lang__") = lang;
|
||||
var.GetAdd(".language") = ToLower(LNGAsText(lang));
|
||||
viewid = bd.id;
|
||||
LDUMP(viewid);
|
||||
(*bd.view)(*this);
|
||||
if(session_dirty)
|
||||
SaveSession();
|
||||
if(SQL.IsOpen())
|
||||
SQL.Commit();
|
||||
}
|
||||
catch(SqlExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Internal server error<br>"
|
||||
<< "SQL ERROR: " << e;
|
||||
code = 500;
|
||||
code_text = "Internal server error";
|
||||
app.SqlError(*this);
|
||||
}
|
||||
catch(AuthExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << e;
|
||||
code = 403;
|
||||
code_text = "Unauthorized";
|
||||
app.Unauthorized(*this);
|
||||
}
|
||||
catch(Exc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Internal server error<br>"
|
||||
<< e;
|
||||
code = 500;
|
||||
code_text = "Internal server error";
|
||||
app.InternalError(*this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
response << "Page not found";
|
||||
code = 404;
|
||||
code_text = "Not found";
|
||||
app.NotFound(*this);
|
||||
}
|
||||
r.Clear();
|
||||
SKYLARKLOG("=== Response: " << code << ' ' << code_text);
|
||||
if(redirect.GetCount()) {
|
||||
SKYLARKLOG("Redirect to: " << redirect);
|
||||
r << "HTTP/1.1 " << code << " Found\r\n";
|
||||
r << "Location: " << redirect << "\r\n";
|
||||
}
|
||||
else {
|
||||
r <<
|
||||
"HTTP/1.0 " << code << ' ' << code_text << "\r\n"
|
||||
"Date: " << WwwFormat(GetUtcTime()) << "\r\n"
|
||||
"Server: U++\r\n"
|
||||
"Content-Length: " << response.GetCount() << "\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Content-Type: " << content_type << "\r\n";
|
||||
for(int i = 0; i < cookies.GetCount(); i++)
|
||||
r << cookies[i];
|
||||
r << "\r\n";
|
||||
}
|
||||
socket.PutAll(r);
|
||||
socket.PutAll(response);
|
||||
}
|
||||
}
|
||||
|
||||
#include "Skylark.h"
|
||||
|
||||
#define LLOG(x) //DLOG(x)
|
||||
#define LDUMP(x) //DDUMP(x)
|
||||
#define LDUMPC(x) //DDUMPC(x)
|
||||
#define LDUMPM(x) //DDUMPM(x)
|
||||
#define LTIMING(x) //RTIMING(x)
|
||||
|
||||
namespace Upp {
|
||||
|
||||
enum { DISPATCH_VARARGS = -1 };
|
||||
|
||||
struct DispatchNode : Moveable<DispatchNode> {
|
||||
VectorMap<String, int> subnode;
|
||||
void (*view)(Http&);
|
||||
int argpos;
|
||||
int method;
|
||||
bool post_raw;
|
||||
String id;
|
||||
|
||||
enum { GET, POST };
|
||||
|
||||
DispatchNode() { view = NULL; argpos = Null; method = GET; post_raw = false; }
|
||||
};
|
||||
|
||||
static Vector<DispatchNode>& sDispatchMap()
|
||||
{
|
||||
static Vector<DispatchNode> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static VectorMap<String, Vector<String> >& sLinkMap()
|
||||
{
|
||||
static VectorMap<String, Vector<String> > x;
|
||||
return x;
|
||||
}
|
||||
|
||||
static Index<uintptr_t>& sViewIndex()
|
||||
{
|
||||
static Index<uintptr_t> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void DumpDispatchMap()
|
||||
{
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
for(int i = 0; i < DispatchMap.GetCount(); i++) {
|
||||
LLOG("-------------");
|
||||
String sub;
|
||||
for(int j = 0; j < DispatchMap[i].subnode.GetCount(); j++)
|
||||
sub << DispatchMap[i].subnode.GetKey(j) << "->" << DispatchMap[i].subnode[j] << ", ";
|
||||
LLOG(i << " " << (bool)DispatchMap[i].view << ": " << sub);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> *GetUrlViewLinkParts(const String& id)
|
||||
{
|
||||
int q = sLinkMap().Find(id);
|
||||
if(q < 0)
|
||||
return NULL;
|
||||
return &sLinkMap()[q];
|
||||
}
|
||||
|
||||
String MakeLink(void (*view)(Http&), const Vector<Value>& arg)
|
||||
{
|
||||
int q = sViewIndex().Find((uintptr_t)view);
|
||||
if(q < 0)
|
||||
throw Exc("Invalid view");
|
||||
if(q < 0)
|
||||
return String();
|
||||
StringBuffer out;
|
||||
MakeLink(out, sLinkMap()[q], arg);
|
||||
return out;
|
||||
}
|
||||
|
||||
void RegisterView0(void (*view)(Http&), const char *id, String path, bool primary)
|
||||
{
|
||||
LLOG("RegisterView " << path);
|
||||
Vector<String>& linkpart = sLinkMap().GetAdd(id);
|
||||
sViewIndex().FindAdd((uintptr_t)view);
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
int method = DispatchNode::GET;
|
||||
bool post_raw = false;
|
||||
int q = path.Find(':');
|
||||
if(q >= 0) {
|
||||
if(path.Mid(q + 1) == "POST")
|
||||
method = DispatchNode::POST;
|
||||
if(path.Mid(q + 1) == "POST_RAW") {
|
||||
method = DispatchNode::POST;
|
||||
post_raw = true;
|
||||
}
|
||||
path = path.Mid(0, q);
|
||||
}
|
||||
Vector<String> h = Split(path, '/');
|
||||
if(DispatchMap.GetCount() == 0)
|
||||
DispatchMap.Add();
|
||||
q = 0;
|
||||
int linkargpos = 0;
|
||||
for(int i = 0; i < h.GetCount(); i++) {
|
||||
String s = h[i];
|
||||
LLOG(" Node " << h[i]);
|
||||
DispatchNode& n = DispatchMap[q];
|
||||
if(*s == '*') {
|
||||
int argpos = Null;
|
||||
if(IsDigit(s[1]))
|
||||
linkargpos = argpos = minmax(atoi(~s + 1), 0, 30);
|
||||
else
|
||||
if(s[1] == '*')
|
||||
argpos = DISPATCH_VARARGS;
|
||||
q = DispatchMap.GetCount();
|
||||
LLOG(" Adding arg " << argpos << ": " << q);
|
||||
n.subnode.Add(Null, q);
|
||||
DispatchMap.Add();
|
||||
DispatchMap[q].argpos = argpos;
|
||||
if(primary)
|
||||
linkpart.Add(String(linkargpos++, 1));
|
||||
}
|
||||
else {
|
||||
if(primary)
|
||||
linkpart.Add(s);
|
||||
q = n.subnode.Get(s, -1);
|
||||
if(q < 0) {
|
||||
q = DispatchMap.GetCount();
|
||||
LLOG(" Adding " << s << ": " << q);
|
||||
n.subnode.Add(s, q);
|
||||
DispatchMap.Add();
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_(!DispatchMap[q].view, "duplicate view " + String(path));
|
||||
DispatchMap[q].view = view;
|
||||
DispatchMap[q].method = method;
|
||||
DispatchMap[q].id = id;
|
||||
DispatchMap[q].post_raw = post_raw;
|
||||
// DumpDispatchMap();
|
||||
}
|
||||
|
||||
struct ViewData {
|
||||
void (*view)(Http&);
|
||||
String id;
|
||||
String path;
|
||||
};
|
||||
|
||||
static Array<ViewData>& sViewData()
|
||||
{
|
||||
static Array<ViewData> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void RegisterHandler(void (*view)(Http&), const char *id, const char *path)
|
||||
{
|
||||
Array<ViewData>& v = sViewData();
|
||||
ViewData& w = v.Add();
|
||||
w.view = view;
|
||||
w.id = id;
|
||||
w.path = path;
|
||||
}
|
||||
|
||||
void SkylarkApp::FinalizeViews()
|
||||
{
|
||||
Array<ViewData>& w = sViewData();
|
||||
for(int i = 0; i < w.GetCount(); i++) {
|
||||
const ViewData& v = w[i];
|
||||
ASSERT_(sViewIndex().Find((uintptr_t)v.view) < 0, "duplicate view function registration " + String(v.id));
|
||||
Vector<String> h = Split(ReplaceVars(root + '/' + v.path, view_var, '$'), ';');
|
||||
for(int i = 0; i < h.GetCount(); i++)
|
||||
RegisterView0(v.view, v.id, h[i], i == 0);
|
||||
}
|
||||
w.Clear();
|
||||
}
|
||||
|
||||
struct BestDispatch {
|
||||
void (*view)(Http&);
|
||||
int matched_parts;
|
||||
int matched_params;
|
||||
Vector<String>& arg;
|
||||
String id;
|
||||
bool post_raw;
|
||||
|
||||
BestDispatch(Vector<String>& arg) : arg(arg) { matched_parts = -1; matched_params = 0; view = NULL; post_raw = false; }
|
||||
};
|
||||
|
||||
void GetBestDispatch(int method,
|
||||
const Vector<String>& part, int ii, const DispatchNode& n, Vector<String>& arg,
|
||||
BestDispatch& bd, int matched_parts, int matched_params)
|
||||
{
|
||||
Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
if(ii >= part.GetCount()) {
|
||||
if(n.view && n.method == method &&
|
||||
(matched_parts > bd.matched_parts ||
|
||||
matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
|
||||
LLOG("Matched " << n.id << " parts " << matched_parts << " params " << matched_params);
|
||||
bd.arg <<= arg;
|
||||
bd.view = n.view;
|
||||
bd.matched_parts = matched_parts;
|
||||
bd.id = n.id;
|
||||
bd.post_raw = n.post_raw;
|
||||
}
|
||||
if(!bd.view) {
|
||||
int q = n.subnode.Find(String());
|
||||
while(q >= 0) {
|
||||
const DispatchNode& an = DispatchMap[n.subnode[q]];
|
||||
if(an.argpos == DISPATCH_VARARGS && an.view && an.method == method) {
|
||||
bd.view = an.view;
|
||||
bd.id = n.id;
|
||||
bd.arg.Clear();
|
||||
break;
|
||||
}
|
||||
q = n.subnode.FindNext(q);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
int qq = n.subnode.Get(part[ii], -1);
|
||||
if(qq >= 0)
|
||||
GetBestDispatch(method, part, ii + 1, DispatchMap[qq], arg, bd, matched_parts + 1, matched_params);
|
||||
int q = n.subnode.Find(String());
|
||||
while(q >= 0) {
|
||||
int qq = n.subnode[q];
|
||||
int ac = arg.GetCount();
|
||||
const DispatchNode& an = DispatchMap[qq];
|
||||
int apos = an.argpos;
|
||||
LLOG(" *" << qq << " apos: " << apos);
|
||||
if(apos == DISPATCH_VARARGS) {
|
||||
if(an.view && an.method == method &&
|
||||
(matched_parts > bd.matched_parts || matched_parts == bd.matched_parts && matched_params > bd.matched_params)) {
|
||||
LLOG("Matched VARARGS " << an.id << " parts " << matched_parts << " params " << matched_params);
|
||||
bd.arg <<= arg;
|
||||
bd.arg.Append(part, ii, part.GetCount() - ii);
|
||||
bd.view = an.view;
|
||||
bd.matched_parts = matched_parts;
|
||||
bd.id = an.id;
|
||||
}
|
||||
}
|
||||
else {
|
||||
String pv;
|
||||
if(IsNull(apos))
|
||||
arg.Add(part[ii]);
|
||||
else {
|
||||
String& at = arg.At(apos);
|
||||
pv = at;
|
||||
at = part[ii];
|
||||
}
|
||||
GetBestDispatch(method, part, ii + 1, an, arg, bd, matched_parts, matched_params + 1);
|
||||
if(!IsNull(apos))
|
||||
arg[apos] = pv;
|
||||
}
|
||||
arg.SetCount(ac);
|
||||
q = n.subnode.FindNext(q);
|
||||
}
|
||||
}
|
||||
|
||||
void Http::Dispatch(TcpSocket& socket)
|
||||
{
|
||||
const Vector<DispatchNode>& DispatchMap = sDispatchMap();
|
||||
if(hdr.Read(socket)) {
|
||||
int len = GetLength();
|
||||
content = socket.GetAll(len);
|
||||
LLOG("--------------------------------------------");
|
||||
SKYLARKLOG(hdr.GetMethod() << " " << hdr.GetURI());
|
||||
LDUMP(content);
|
||||
String r;
|
||||
var.Clear();
|
||||
arg.Clear();
|
||||
LTIMING("Request processing");
|
||||
request_content_type = GetHeader("content-type");
|
||||
String rc = ToLower(request_content_type);
|
||||
bool post = hdr.GetMethod() == "POST";
|
||||
if(post)
|
||||
if(rc.StartsWith("application/x-www-form-urlencoded"))
|
||||
ParseRequest(content);
|
||||
else
|
||||
if(rc.StartsWith("multipart/"))
|
||||
ReadMultiPart(content);
|
||||
String uri = hdr.GetURI();
|
||||
int q = uri.Find('?');
|
||||
if(q >= 0) {
|
||||
if(!post)
|
||||
ParseRequest(~uri + q + 1);
|
||||
uri.Trim(q);
|
||||
}
|
||||
for(int i = hdr.fields.Find("cookie"); i >= 0; i = hdr.fields.FindNext(i)) {
|
||||
const String& h = hdr.fields[i];
|
||||
int q = 0;
|
||||
for(;;) {
|
||||
int qq = h.Find('=', q);
|
||||
if(qq < 0)
|
||||
break;
|
||||
String id = ToLower(TrimBoth(h.Mid(q, qq - q)));
|
||||
qq++;
|
||||
q = h.Find(';', qq);
|
||||
if(q < 0) {
|
||||
var.Add('@' + id, UrlDecode(h.Mid(qq)));
|
||||
break;
|
||||
}
|
||||
var.Add('@' + id, UrlDecode(h.Mid(qq, q - qq)));
|
||||
q++;
|
||||
}
|
||||
}
|
||||
var.GetAdd("static") = app.static_dir;
|
||||
var.GetAdd(".__identity__"); // To make StdLib.icpp GetIndentity work without changing preset stack positions
|
||||
LDUMPM(var);
|
||||
Vector<String> part = Split(uri, '/');
|
||||
for(int i = 0; i < part.GetCount(); i++)
|
||||
part[i] = UrlDecode(part[i]);
|
||||
LDUMPC(part);
|
||||
Vector<String> a;
|
||||
BestDispatch bd(arg);
|
||||
if(DispatchMap.GetCount())
|
||||
GetBestDispatch(post ? DispatchNode::POST : DispatchNode::GET, part, 0, DispatchMap[0], a, bd, 0, 0);
|
||||
LDUMPC(arg);
|
||||
response.Clear();
|
||||
if(bd.view) {
|
||||
try {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Begin();
|
||||
LoadSession();
|
||||
session_dirty = false;
|
||||
if(post && !bd.post_raw) {
|
||||
String id = Nvl((*this)["__post_identity__"], (*this)["__js_identity__"]);
|
||||
if(id != (*this)[".__identity__"])
|
||||
throw AuthExc("identity error");
|
||||
}
|
||||
lang = Nvl(Int(".__lang__"), LNG_ENGLISH);
|
||||
Upp::SetLanguage(lang);
|
||||
var.GetAdd(".__lang__") = lang;
|
||||
var.GetAdd(".language") = ToLower(LNGAsText(lang));
|
||||
viewid = bd.id;
|
||||
LDUMP(viewid);
|
||||
(*bd.view)(*this);
|
||||
if(session_dirty)
|
||||
SaveSession();
|
||||
if(SQL.IsOpen())
|
||||
SQL.Commit();
|
||||
}
|
||||
catch(SqlExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Internal server error<br>"
|
||||
<< "SQL ERROR: " << e;
|
||||
code = 500;
|
||||
code_text = "Internal server error";
|
||||
app.SqlError(*this);
|
||||
}
|
||||
catch(AuthExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << e;
|
||||
code = 403;
|
||||
code_text = "Unauthorized";
|
||||
app.Unauthorized(*this);
|
||||
}
|
||||
catch(BadRequestExc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Bad request";
|
||||
code = 400;
|
||||
code_text = "Bad request";
|
||||
app.Unauthorized(*this);
|
||||
}
|
||||
catch(Exc e) {
|
||||
if(SQL.IsOpen())
|
||||
SQL.Rollback();
|
||||
response << "Internal server error<br>"
|
||||
<< e;
|
||||
code = 500;
|
||||
code_text = "Internal server error";
|
||||
app.InternalError(*this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
response << "Page not found";
|
||||
code = 404;
|
||||
code_text = "Not found";
|
||||
app.NotFound(*this);
|
||||
}
|
||||
r.Clear();
|
||||
SKYLARKLOG("=== Response: " << code << ' ' << code_text);
|
||||
if(redirect.GetCount()) {
|
||||
SKYLARKLOG("Redirect to: " << redirect);
|
||||
r << "HTTP/1.1 " << code << " Found\r\n";
|
||||
r << "Location: " << redirect << "\r\n";
|
||||
}
|
||||
else {
|
||||
r <<
|
||||
"HTTP/1.0 " << code << ' ' << code_text << "\r\n"
|
||||
"Date: " << WwwFormat(GetUtcTime()) << "\r\n"
|
||||
"Server: U++\r\n"
|
||||
"Content-Length: " << response.GetCount() << "\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Content-Type: " << content_type << "\r\n";
|
||||
for(int i = 0; i < cookies.GetCount(); i++)
|
||||
r << cookies[i];
|
||||
r << "\r\n";
|
||||
}
|
||||
socket.PutAll(r);
|
||||
socket.PutAll(response);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,142 +1,144 @@
|
|||
void MakeLink(StringBuffer& out, const Vector<String>& part, const Vector<Value>& arg);
|
||||
|
||||
class Renderer {
|
||||
protected:
|
||||
VectorMap<String, Value> var;
|
||||
int lang;
|
||||
|
||||
Renderer& Link(const char *id, void (*view)(Http&), const Vector<Value>& arg);
|
||||
const One<Exe>& GetTemplate(const char *template_name);
|
||||
|
||||
public:
|
||||
Renderer& operator()(const char *id, const Value& v) { var.Add(id, v); return *this; }
|
||||
Renderer& operator()(const ValueMap& map);
|
||||
Renderer& operator()(const char *id, void (*view)(Http&));
|
||||
Renderer& operator()(const char *id, void (*view)(Http&), const Value& arg1);
|
||||
Renderer& operator()(const char *id, void (*view)(Http&), const Value& arg1, const Value& arg2);
|
||||
|
||||
Renderer& operator()(const Sql& sql);
|
||||
Renderer& operator()(Fields rec);
|
||||
SqlUpdate Update(SqlId table);
|
||||
SqlInsert Insert(SqlId table);
|
||||
|
||||
Value operator[](const char *id) const { return var.Get(id, Null); }
|
||||
|
||||
String RenderString(const String& template_name);
|
||||
Value Render(const String& template_name) { return Raw(RenderString(template_name)); }
|
||||
|
||||
Renderer& Render(const char *id, const String& template_name);
|
||||
|
||||
Renderer() { lang = LNG_ENGLISH; }
|
||||
virtual ~Renderer();
|
||||
};
|
||||
|
||||
class Http : public Renderer {
|
||||
SkylarkApp& app;
|
||||
HttpHeader hdr;
|
||||
|
||||
String content;
|
||||
String viewid;
|
||||
|
||||
Vector<String> arg;
|
||||
String session_id;
|
||||
VectorMap<String, Value> session_var;
|
||||
bool session_dirty;
|
||||
|
||||
String redirect;
|
||||
int code;
|
||||
String code_text;
|
||||
String response;
|
||||
String content_type;
|
||||
String request_content_type;
|
||||
|
||||
VectorMap<String, String> cookies;
|
||||
|
||||
void ParseRequest(const char *s);
|
||||
void ReadMultiPart(const String& content);
|
||||
|
||||
String SessionFile(const String& sid);
|
||||
|
||||
void LoadSession();
|
||||
void SaveSession();
|
||||
|
||||
public:
|
||||
Http& operator()(const char *id, const Value& v) { var.Add(id, v); return *this; }
|
||||
Http& operator()(const ValueMap& map) { Renderer::operator()(map); return *this; }
|
||||
Http& operator()(const char *id, void (*view)(Http&)) { Renderer::operator()(id, view); return *this; }
|
||||
Http& operator()(const char *id, void (*view)(Http&), const Value& arg1) { Renderer::operator()(id, view, arg1); return *this; }
|
||||
Http& operator()(const char *id, void (*view)(Http&), const Value& arg1, const Value& arg2) { Renderer::operator()(id, view, arg1, arg2); return *this; }
|
||||
|
||||
Http& operator()(const Sql& sql) { Renderer::operator()(sql); return *this; }
|
||||
Http& operator()(Fields rec) { Renderer::operator()(rec); return *this; }
|
||||
Http& Render(const char *id, const String& template_name) { Renderer::Render(id, template_name); return *this; }
|
||||
Value Render(const String& template_name) { return Renderer::Render(template_name); }
|
||||
|
||||
void Dispatch(TcpSocket& socket);
|
||||
|
||||
String GetHeader(const char *s) const { return hdr[s]; }
|
||||
int GetLength() const { return atoi(GetHeader("content-length")); }
|
||||
|
||||
String GetViewId() const { return viewid; }
|
||||
|
||||
Value operator[](const char *id) const { return Renderer::operator[](id); }
|
||||
String operator[](int i) const { return i >= 0 && i < arg.GetCount() ? arg[i] : String(); }
|
||||
|
||||
int Int(const char *id) const;
|
||||
int Int(int i) const;
|
||||
|
||||
int GetParamCount() const { return arg.GetCount(); }
|
||||
|
||||
Http& ContentType(const char *s) { content_type = s; return *this; }
|
||||
|
||||
Http& Content(const char *s, const Value& data);
|
||||
Http& operator<<(const Value& s);
|
||||
|
||||
Http& SetRawCookie(const char *id, const String& value,
|
||||
Time expires = Null, const char *path = NULL,
|
||||
const char *domain = NULL, bool secure = false, bool httponly = false);
|
||||
Http& SetCookie(const char *id, const String& value,
|
||||
Time expires = Null, const char *path = NULL,
|
||||
const char *domain = NULL, bool secure = false, bool httponly = false);
|
||||
|
||||
Http& ClearSession();
|
||||
Http& SessionSet(const char *id, const Value& value);
|
||||
|
||||
Http& NewIdentity() { SessionSet("__identity__", Null); return *this; }
|
||||
Http& NewSessionId();
|
||||
Http& SetLanguage(int lang);
|
||||
|
||||
Http& Response(int code_, const String& ctext) { code = code_; code_text = ctext; return *this; }
|
||||
|
||||
Http& RenderResult(const char *template_name);
|
||||
Http& Redirect(const char *url, int code_ = 302) { code = code_; redirect = url; return *this; }
|
||||
Http& Redirect(void (*view)(Http&), const Vector<Value>& arg);
|
||||
Http& Redirect(void (*view)(Http&));
|
||||
Http& Redirect(void (*view)(Http&), const Value& v1);
|
||||
Http& Redirect(void (*view)(Http&), const Value& v1, const Value& v2);
|
||||
|
||||
Http& Ux(const char *id, const String& text);
|
||||
Http& UxRender(const char *id, const char *template_name);
|
||||
Http& UxSet(const char *id, const String& value);
|
||||
Http& UxRun(const String& js_code);
|
||||
|
||||
String GetResponse() const { return response; }
|
||||
|
||||
const SkylarkApp& App() const { return app; }
|
||||
|
||||
Http(SkylarkApp& app);
|
||||
};
|
||||
|
||||
String HttpResponse(int code, const char *phrase, const String& data, const char *content_type = NULL);
|
||||
|
||||
void RegisterView(void (*view)(Http&), const char *id, const char *path);
|
||||
|
||||
#define SKYLARK(name, path) void name(Http& http); INITBLOCK { UPP::RegisterView(name, #name, path); } void name(Http& http)
|
||||
|
||||
Vector<String> *GetUrlViewLinkParts(const String& id);
|
||||
|
||||
String MakeLink(void (*view)(Http&), const Vector<Value>& arg);
|
||||
|
||||
enum {
|
||||
SESSION_FORMAT_BINARY, SESSION_FORMAT_JSON, SESSION_FORMAT_XML
|
||||
};
|
||||
void MakeLink(StringBuffer& out, const Vector<String>& part, const Vector<Value>& arg);
|
||||
|
||||
class Renderer {
|
||||
protected:
|
||||
VectorMap<String, Value> var;
|
||||
int lang;
|
||||
|
||||
Renderer& Link(const char *id, void (*view)(Http&), const Vector<Value>& arg);
|
||||
const One<Exe>& GetTemplate(const char *template_name);
|
||||
|
||||
public:
|
||||
Renderer& operator()(const char *id, const Value& v) { var.Add(id, v); return *this; }
|
||||
Renderer& operator()(const ValueMap& map);
|
||||
Renderer& operator()(const char *id, void (*view)(Http&));
|
||||
Renderer& operator()(const char *id, void (*view)(Http&), const Value& arg1);
|
||||
Renderer& operator()(const char *id, void (*view)(Http&), const Value& arg1, const Value& arg2);
|
||||
|
||||
Renderer& operator()(const Sql& sql);
|
||||
Renderer& operator()(Fields rec);
|
||||
Renderer& operator()(const SqlSelect& row_sel);
|
||||
Renderer& operator()(const char *id, const SqlSelect& sel);
|
||||
SqlUpdate Update(SqlId table);
|
||||
SqlInsert Insert(SqlId table);
|
||||
|
||||
Value operator[](const char *id) const { return var.Get(id, Null); }
|
||||
|
||||
String RenderString(const String& template_name);
|
||||
Value Render(const String& template_name) { return Raw(RenderString(template_name)); }
|
||||
|
||||
Renderer& Render(const char *id, const String& template_name);
|
||||
|
||||
Renderer() { lang = LNG_ENGLISH; }
|
||||
virtual ~Renderer();
|
||||
};
|
||||
|
||||
class Http : public Renderer {
|
||||
SkylarkApp& app;
|
||||
HttpHeader hdr;
|
||||
|
||||
String content;
|
||||
String viewid;
|
||||
|
||||
Vector<String> arg;
|
||||
String session_id;
|
||||
VectorMap<String, Value> session_var;
|
||||
bool session_dirty;
|
||||
|
||||
String redirect;
|
||||
int code;
|
||||
String code_text;
|
||||
String response;
|
||||
String content_type;
|
||||
String request_content_type;
|
||||
|
||||
VectorMap<String, String> cookies;
|
||||
|
||||
void ParseRequest(const char *s);
|
||||
void ReadMultiPart(const String& content);
|
||||
|
||||
String SessionFile(const String& sid);
|
||||
|
||||
void LoadSession();
|
||||
void SaveSession();
|
||||
|
||||
public:
|
||||
Http& operator()(const char *id, const Value& v) { var.Add(id, v); return *this; }
|
||||
Http& operator()(const ValueMap& map) { Renderer::operator()(map); return *this; }
|
||||
Http& operator()(const char *id, void (*view)(Http&)) { Renderer::operator()(id, view); return *this; }
|
||||
Http& operator()(const char *id, void (*view)(Http&), const Value& arg1) { Renderer::operator()(id, view, arg1); return *this; }
|
||||
Http& operator()(const char *id, void (*view)(Http&), const Value& arg1, const Value& arg2) { Renderer::operator()(id, view, arg1, arg2); return *this; }
|
||||
|
||||
Http& operator()(const Sql& sql) { Renderer::operator()(sql); return *this; }
|
||||
Http& operator()(Fields rec) { Renderer::operator()(rec); return *this; }
|
||||
Http& operator()(const SqlSelect& row_sel) { Renderer::operator()(row_sel); return *this; }
|
||||
Http& operator()(const char *id, const SqlSelect& sel) { Renderer::operator()(id, sel); return *this; }
|
||||
Http& Render(const char *id, const String& template_name) { Renderer::Render(id, template_name); return *this; }
|
||||
Value Render(const String& template_name) { return Renderer::Render(template_name); }
|
||||
|
||||
String GetHeader(const char *s) const { return hdr[s]; }
|
||||
int GetLength() const { return atoi(GetHeader("content-length")); }
|
||||
|
||||
String GetViewId() const { return viewid; }
|
||||
|
||||
Value operator[](const char *id) const { return Renderer::operator[](id); }
|
||||
int Int(const char *id) const;
|
||||
|
||||
String operator[](int i) const { return i >= 0 && i < arg.GetCount() ? arg[i] : String(); }
|
||||
int Int(int i) const;
|
||||
|
||||
int GetParamCount() const { return arg.GetCount(); }
|
||||
|
||||
Http& ContentType(const char *s) { content_type = s; return *this; }
|
||||
|
||||
Http& Content(const char *s, const Value& data);
|
||||
Http& operator<<(const Value& s);
|
||||
|
||||
Http& SetRawCookie(const char *id, const String& value,
|
||||
Time expires = Null, const char *path = NULL,
|
||||
const char *domain = NULL, bool secure = false, bool httponly = false);
|
||||
Http& SetCookie(const char *id, const String& value,
|
||||
Time expires = Null, const char *path = NULL,
|
||||
const char *domain = NULL, bool secure = false, bool httponly = false);
|
||||
|
||||
Http& ClearSession();
|
||||
Http& SessionSet(const char *id, const Value& value);
|
||||
|
||||
Http& NewIdentity() { SessionSet("__identity__", Null); return *this; }
|
||||
Http& NewSessionId();
|
||||
Http& SetLanguage(int lang);
|
||||
|
||||
Http& Response(int code_, const String& ctext) { code = code_; code_text = ctext; return *this; }
|
||||
|
||||
Http& RenderResult(const char *template_name);
|
||||
Http& Redirect(const char *url, int code_ = 302) { code = code_; redirect = url; return *this; }
|
||||
Http& Redirect(void (*view)(Http&), const Vector<Value>& arg);
|
||||
Http& Redirect(void (*view)(Http&));
|
||||
Http& Redirect(void (*view)(Http&), const Value& v1);
|
||||
Http& Redirect(void (*view)(Http&), const Value& v1, const Value& v2);
|
||||
|
||||
Http& Ux(const char *id, const String& text);
|
||||
Http& UxRender(const char *id, const char *template_name);
|
||||
Http& UxSet(const char *id, const String& value);
|
||||
Http& UxRun(const String& js_code);
|
||||
|
||||
String GetResponse() const { return response; }
|
||||
|
||||
void Dispatch(TcpSocket& socket);
|
||||
|
||||
const SkylarkApp& App() const { return app; }
|
||||
|
||||
Http(SkylarkApp& app);
|
||||
};
|
||||
|
||||
void RegisterHandler(void (*handler)(Http& http), const char *id, const char *path);
|
||||
|
||||
#define SKYLARK(name, path) void name(Http& http); INITBLOCK { UPP::RegisterHandler(name, #name, path); } void name(Http& http)
|
||||
|
||||
Vector<String> *GetUrlViewLinkParts(const String& id);
|
||||
|
||||
String MakeLink(void (*view)(Http&), const Vector<Value>& arg);
|
||||
|
||||
enum {
|
||||
SESSION_FORMAT_BINARY, SESSION_FORMAT_JSON, SESSION_FORMAT_XML
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#ifndef _Iml_Iml_h
|
||||
#define _Iml_Iml_h
|
||||
|
||||
#include <Draw/Draw.h>
|
||||
#include <plugin/png/png.h>
|
||||
#include <plugin/jpg/jpg.h>
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#ifndef _Iml_Iml_h
|
||||
#define _Iml_Iml_h
|
||||
|
||||
#include <Draw/Draw.h>
|
||||
#include <plugin/png/png.h>
|
||||
#include <plugin/jpg/jpg.h>
|
||||
#include <Skylark/Skylark.h>
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
description "\377128,0,0";
|
||||
|
||||
uses
|
||||
Draw,
|
||||
plugin\png,
|
||||
plugin\jpg;
|
||||
|
||||
file
|
||||
Iml.h,
|
||||
Lib.icpp;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef _Skylark_Iml_icpp_init_stub
|
||||
#define _Skylark_Iml_icpp_init_stub
|
||||
#define BLITZ_INDEX__ F565e623033e15f6c077dba0bc03cb2ea
|
||||
#include "Draw/init"
|
||||
#include "plugin\png/init"
|
||||
#include "plugin\jpg/init"
|
||||
#define BLITZ_INDEX__ F2cfe659668367946f7f2baa1fbeb2b5e
|
||||
#include "Lib.icpp"
|
||||
#undef BLITZ_INDEX__
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,96 +1,99 @@
|
|||
#ifndef _Wpp_Wpp_h
|
||||
#define _Wpp_Wpp_h
|
||||
|
||||
#include <Sql/Sql.h>
|
||||
|
||||
namespace Upp {
|
||||
|
||||
namespace Ini {
|
||||
extern IniBool skylark_log;
|
||||
};
|
||||
|
||||
String GetThreadName();
|
||||
|
||||
#define SKYLARKLOG(x) LOG_(Ini::skylark_log, GetThreadName() << ' ' << x)
|
||||
|
||||
class Renderer;
|
||||
class Http;
|
||||
|
||||
struct SessionConfig {
|
||||
String cookie;
|
||||
String dir;
|
||||
int format;
|
||||
SqlId table, id_column, data_column, lastwrite_column;
|
||||
int expire;
|
||||
|
||||
SessionConfig();
|
||||
};
|
||||
|
||||
struct AuthExc : Exc {
|
||||
AuthExc(const String& s) : Exc(s) {}
|
||||
};
|
||||
|
||||
struct SkylarkConfig {
|
||||
String root;
|
||||
VectorMap<String, String> view_var;
|
||||
String path;
|
||||
String static_dir;
|
||||
SessionConfig session;
|
||||
int threads;
|
||||
int port;
|
||||
int prefork;
|
||||
int timeout;
|
||||
bool use_caching;
|
||||
};
|
||||
|
||||
class SkylarkApp : protected SkylarkConfig {
|
||||
TcpSocket server;
|
||||
Mutex accept_mutex;
|
||||
int main_pid;
|
||||
Vector<int> child_pid;
|
||||
bool quit;
|
||||
|
||||
|
||||
void ThreadRun();
|
||||
void Broadcast(int signal);
|
||||
void Signal(int signal);
|
||||
static void SignalHandler(int signal);
|
||||
void Main();
|
||||
|
||||
void FinalizeViews();
|
||||
|
||||
static SkylarkApp *app;
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
static BOOL WINAPI CtrlCHandlerRoutine(__in DWORD dwCtrlType);
|
||||
#endif
|
||||
|
||||
typedef SkylarkApp CLASSNAME;
|
||||
|
||||
friend class Http;
|
||||
|
||||
public:
|
||||
virtual void SqlError(Http& http);
|
||||
virtual void InternalError(Http& http);
|
||||
virtual void NotFound(Http& http);
|
||||
virtual void Unauthorized(Http& http);
|
||||
|
||||
virtual void WorkThread();
|
||||
|
||||
void RunThread();
|
||||
|
||||
void Run();
|
||||
|
||||
static SkylarkApp& TheApp();
|
||||
static const SkylarkConfig& Config();
|
||||
|
||||
SkylarkApp();
|
||||
virtual ~SkylarkApp();
|
||||
};
|
||||
|
||||
#include "Witz.h"
|
||||
#include "Http.h"
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
#ifndef _Skylark_Skylark_h
|
||||
#define _Skylark_Skylark_h
|
||||
|
||||
#include <Sql/Sql.h>
|
||||
|
||||
namespace Upp {
|
||||
|
||||
namespace Ini {
|
||||
extern IniBool skylark_log;
|
||||
};
|
||||
|
||||
String GetThreadName();
|
||||
|
||||
#define SKYLARKLOG(x) LOG_(Ini::skylark_log, GetThreadName() << ' ' << x)
|
||||
|
||||
class Renderer;
|
||||
class Http;
|
||||
|
||||
struct SessionConfig {
|
||||
String cookie;
|
||||
String dir;
|
||||
int format;
|
||||
SqlId table, id_column, data_column, lastwrite_column;
|
||||
int expire;
|
||||
|
||||
SessionConfig();
|
||||
};
|
||||
|
||||
struct AuthExc : Exc {
|
||||
AuthExc(const String& s) : Exc(s) {}
|
||||
};
|
||||
|
||||
struct BadRequestExc : Exc {};
|
||||
|
||||
struct SkylarkConfig {
|
||||
String root;
|
||||
VectorMap<String, String> view_var;
|
||||
String path;
|
||||
String static_dir;
|
||||
SessionConfig session;
|
||||
int threads;
|
||||
int port;
|
||||
int prefork;
|
||||
int timeout;
|
||||
bool use_caching;
|
||||
};
|
||||
|
||||
class SkylarkApp : protected SkylarkConfig {
|
||||
TcpSocket server;
|
||||
Mutex accept_mutex;
|
||||
int main_pid;
|
||||
Vector<int> child_pid;
|
||||
bool quit;
|
||||
|
||||
|
||||
void ThreadRun();
|
||||
void Broadcast(int signal);
|
||||
void Signal(int signal);
|
||||
static void SignalHandler(int signal);
|
||||
void Main();
|
||||
|
||||
void FinalizeViews();
|
||||
|
||||
static SkylarkApp *app;
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
static BOOL WINAPI CtrlCHandlerRoutine(__in DWORD dwCtrlType);
|
||||
#endif
|
||||
|
||||
typedef SkylarkApp CLASSNAME;
|
||||
|
||||
friend class Http;
|
||||
|
||||
public:
|
||||
virtual void SqlError(Http& http);
|
||||
virtual void InternalError(Http& http);
|
||||
virtual void NotFound(Http& http);
|
||||
virtual void Unauthorized(Http& http);
|
||||
virtual void BadRequest(Http& http);
|
||||
|
||||
virtual void WorkThread();
|
||||
|
||||
void RunThread();
|
||||
|
||||
void Run();
|
||||
|
||||
static SkylarkApp& TheApp();
|
||||
static const SkylarkConfig& Config();
|
||||
|
||||
SkylarkApp();
|
||||
virtual ~SkylarkApp();
|
||||
};
|
||||
|
||||
#include "Witz.h"
|
||||
#include "Http.h"
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,60 +1,80 @@
|
|||
#include "Skylark.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
struct sFieldsToRenderer : public FieldOperator {
|
||||
Renderer& http;
|
||||
|
||||
void Field(const char *name, Ref f) {
|
||||
http(name, f);
|
||||
}
|
||||
|
||||
sFieldsToRenderer(Renderer& http) : http(http) {}
|
||||
};
|
||||
|
||||
Renderer& Renderer::operator()(Fields rec)
|
||||
{
|
||||
sFieldsToRenderer x(*this);
|
||||
rec(x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Renderer& Renderer::operator()(const Sql& sql)
|
||||
{
|
||||
int n = sql.GetColumns();
|
||||
for(int i = 0; i < n; i++)
|
||||
(*this)(sql.GetColumnInfo(i).name, sql[i]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SqlUpdate Renderer::Update(SqlId table)
|
||||
{
|
||||
Vector<String> col = GetSchColumns(~table);
|
||||
SqlUpdate u(table);
|
||||
for(int i = 0; i < col.GetCount(); i++) {
|
||||
String c = col[i];
|
||||
int q = var.Find(c);
|
||||
if(q < 0)
|
||||
q = var.Find(ToLower(c));
|
||||
if(q >= 0)
|
||||
u(c, var[q]);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
SqlInsert Renderer::Insert(SqlId table)
|
||||
{
|
||||
Vector<String> col = GetSchColumns(~table);
|
||||
SqlInsert y(table);
|
||||
for(int i = 0; i < col.GetCount(); i++) {
|
||||
String c = col[i];
|
||||
int q = var.Find(c);
|
||||
if(q < 0)
|
||||
q = var.Find(ToLower(c));
|
||||
if(q >= 0)
|
||||
y(c, var[q]);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
#include "Skylark.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
struct sFieldsToRenderer : public FieldOperator {
|
||||
Renderer& http;
|
||||
|
||||
void Field(const char *name, Ref f) {
|
||||
http(name, f);
|
||||
}
|
||||
|
||||
sFieldsToRenderer(Renderer& http) : http(http) {}
|
||||
};
|
||||
|
||||
Renderer& Renderer::operator()(Fields rec)
|
||||
{
|
||||
sFieldsToRenderer x(*this);
|
||||
rec(x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Renderer& Renderer::operator()(const Sql& sql)
|
||||
{
|
||||
int n = sql.GetColumns();
|
||||
for(int i = 0; i < n; i++)
|
||||
(*this)(sql.GetColumnInfo(i).name, sql[i]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Renderer& Renderer::operator()(const SqlSelect& sel)
|
||||
{
|
||||
SqlR sql;
|
||||
sql * sel;
|
||||
if(!sql.Fetch())
|
||||
throw BadRequestExc();
|
||||
return operator()(sql);
|
||||
}
|
||||
|
||||
Renderer& Renderer::operator()(const char *id, const SqlSelect& sel)
|
||||
{
|
||||
ValueArray list;
|
||||
ValueMap vm;
|
||||
SqlR sql;
|
||||
sql * sel;
|
||||
while(sql.Fetch(vm))
|
||||
list.Add(vm);
|
||||
return operator()(id, list);
|
||||
}
|
||||
|
||||
SqlUpdate Renderer::Update(SqlId table)
|
||||
{
|
||||
Vector<String> col = GetSchColumns(~table);
|
||||
SqlUpdate u(table);
|
||||
for(int i = 0; i < col.GetCount(); i++) {
|
||||
String c = col[i];
|
||||
int q = var.Find(c);
|
||||
if(q < 0)
|
||||
q = var.Find(ToLower(c));
|
||||
if(q >= 0)
|
||||
u(c, var[q]);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
SqlInsert Renderer::Insert(SqlId table)
|
||||
{
|
||||
Vector<String> col = GetSchColumns(~table);
|
||||
SqlInsert y(table);
|
||||
for(int i = 0; i < col.GetCount(); i++) {
|
||||
String c = col[i];
|
||||
int q = var.Find(c);
|
||||
if(q < 0)
|
||||
q = var.Find(ToLower(c));
|
||||
if(q >= 0)
|
||||
y(c, var[q]);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -590,4 +590,347 @@ the value attribute of matching element. Not shown here, [*@5 UxRender]
|
|||
is similar to Ux, but renders the text from witz template and
|
||||
finally [*@5 UxRun] can be used to run any JavaScript code in the
|
||||
client.&]
|
||||
[s5; ]]
|
||||
[s5; &]
|
||||
[s3; 9. Connecting SQL database&]
|
||||
[s5; Skylark naturally uses U`+`+ SQL support when dealing with persistent
|
||||
storage, using `"session per`-thread`" mode. Because of this,
|
||||
database session needs to be connected when starting each thread
|
||||
`- this is done by overloading [@5 WorkThread] virtual method of
|
||||
SkylarkApp:&]
|
||||
[s7; &]
|
||||
[s7; &]
|
||||
[s7; #include <Skylark/Skylark.h>&]
|
||||
[s7; #include <plugin/sqlite3/Sqlite3.h>&]
|
||||
[s7; &]
|
||||
[s7; using namespace Upp;&]
|
||||
[s7; &]
|
||||
[s7; #define MODEL <Skylark09/myapp.sch>&]
|
||||
[s7; #define SCHEMADIALECT <plugin/sqlite3/Sqlite3Schema.h>&]
|
||||
[s7; #include <Sql/sch`_header.h>&]
|
||||
[s7; #include <Sql/sch`_schema.h>&]
|
||||
[s7; #include <Sql/sch`_source.h>&]
|
||||
[s7; &]
|
||||
[s7; SKYLARK(HomePage, `"`")&]
|
||||
[s7; `{&]
|
||||
[s7; -|Sql sql;&]
|
||||
[s7; -|sql `* Select(ID, NAME, LASTNAME)&]
|
||||
[s7; -| .From(PERSON)&]
|
||||
[s7; -| .OrderBy(LASTNAME, NAME);&]
|
||||
[s7; -|ValueArray person;&]
|
||||
[s7; -|ValueMap vm;&]
|
||||
[s7; -|while(sql.Fetch(vm))&]
|
||||
[s7; -|-|person.Add(vm);&]
|
||||
[s7; -|http(`"PERSON`", person)&]
|
||||
[s7; -| .RenderResult(`"Skylark09/index`");&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; struct MyApp : SkylarkApp `{&]
|
||||
[s7; -|[* virtual void WorkThread();]&]
|
||||
[s7; &]
|
||||
[s7; -|MyApp() `{&]
|
||||
[s7; -|-|root `= `"myapp`";&]
|
||||
[s7; -|-|threads `= 1; // Sqlite3 does not like threads...&]
|
||||
[s7; -|#ifdef `_DEBUG&]
|
||||
[s7; -|-|prefork `= 0;&]
|
||||
[s7; -|-|use`_caching `= false;&]
|
||||
[s7; -|#endif&]
|
||||
[s7; -|`}&]
|
||||
[s7; `};&]
|
||||
[s7; &]
|
||||
[s7; void InitModel()&]
|
||||
[s7; `{&]
|
||||
[s7; #ifdef `_DEBUG&]
|
||||
[s7; -|SqlSchema sch(SQLITE3);&]
|
||||
[s7; -|All`_Tables(sch);&]
|
||||
[s7; -|SqlPerformScript(sch.Upgrade());&]
|
||||
[s7; -|SqlPerformScript(sch.Attributes());&]
|
||||
[s7; -|sch.SaveNormal();&]
|
||||
[s7; #endif&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; void OpenSQL(Sqlite3Session`& sqlite3)&]
|
||||
[s7; `{&]
|
||||
[s7; -|if(!sqlite3.Open(ConfigFile(`"db`"))) `{&]
|
||||
[s7; -|-|LOG(`"Can`'t create or open database file`\n`");&]
|
||||
[s7; -|-|Exit(1);&]
|
||||
[s7; -|`}&]
|
||||
[s7; #ifdef `_DEBUG&]
|
||||
[s7; -|sqlite3.LogErrors();&]
|
||||
[s7; -|sqlite3.SetTrace();&]
|
||||
[s7; #endif&]
|
||||
[s7; -|SQL `= sqlite3;&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; [* void MyApp`::WorkThread()]&]
|
||||
[s7; [* `{]&]
|
||||
[s7; [* -|Sqlite3Session sqlite3;]&]
|
||||
[s7; [* -|OpenSQL(sqlite3);]&]
|
||||
[s7; [* -|RunThread();]&]
|
||||
[s7; [* `}]&]
|
||||
[s7; &]
|
||||
[s7; void InitDB()&]
|
||||
[s7; `{&]
|
||||
[s7; -|Sqlite3Session sqlsession;&]
|
||||
[s7; -|OpenSQL(sqlsession);&]
|
||||
[s7; -|SqlSchema sch(SQLITE3);&]
|
||||
[s7; -|All`_Tables(sch);&]
|
||||
[s7; -|SqlPerformScript(sch.Upgrade());&]
|
||||
[s7; -|SqlPerformScript(sch.Attributes());&]
|
||||
[s7; &]
|
||||
[s7; -|SQL `* Insert(PERSON)(NAME,`"Joe`")(LASTNAME,`"Smith`");&]
|
||||
[s7; -|SQL `* Insert(PERSON)(NAME,`"Mike`")(LASTNAME,`"Carpenter`");&]
|
||||
[s7; -|SQL `* Insert(PERSON)(NAME,`"Jon`")(LASTNAME,`"Goober`");&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; CONSOLE`_APP`_MAIN&]
|
||||
[s7; `{&]
|
||||
[s7; #ifdef `_DEBUG&]
|
||||
[s7; -|StdLogSetup(LOG`_FILE`|LOG`_COUT);&]
|
||||
[s7; -|Ini`::skylark`_log `= true;&]
|
||||
[s7; #endif&]
|
||||
[s7; &]
|
||||
[s7; -|DeleteFile(ConfigFile(`"db`")); // for this example, always
|
||||
create a new DB&]
|
||||
[s7; -|InitDB();&]
|
||||
[s7; &]
|
||||
[s7; -|MyApp().Run();-|&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; &]
|
||||
[s5; [* Skylark09/index.witz:]&]
|
||||
[s7; <html>&]
|
||||
[s7; <body>&]
|
||||
[s7; <table border`=`"1`">&]
|
||||
[s7; <tr>&]
|
||||
[s7; <th>No.</th>&]
|
||||
[s7; <th>First Name</th>&]
|
||||
[s7; <th>Last Name</th>&]
|
||||
[s7; </tr>&]
|
||||
[s7; `$for(i in PERSON)&]
|
||||
[s7; -|<tr>&]
|
||||
[s7; -| <td>`$i.`_index.</td>&]
|
||||
[s7; -| <td>`$i.NAME</td>&]
|
||||
[s7; -| <td>`$i.LASTNAME</td>&]
|
||||
[s7; -|</tr>-|&]
|
||||
[s7; `$/&]
|
||||
[s7; </table>&]
|
||||
[s7; </body>&]
|
||||
[s7; </html>&]
|
||||
[s7; &]
|
||||
[s7; &]
|
||||
[s5; [* Skylark09/myapp.sch:]&]
|
||||
[s7; TABLE`_(PERSON)&]
|
||||
[s7; -|INT`_ (ID) PRIMARY`_KEY AUTO`_INCREMENT&]
|
||||
[s7; -|STRING`_ (NAME, 200)&]
|
||||
[s7; -|STRING`_ (LASTNAME, 200)&]
|
||||
[s7; END`_TABLE&]
|
||||
[s7; &]
|
||||
[s7; &]
|
||||
[s3; 10. Advanced SQL&]
|
||||
[s5; Http class contains some advanced convenience support for dealing
|
||||
with SQL databases:&]
|
||||
[s5;i150;O0; It is possible to fill result set of SqlSelect into
|
||||
witz variable as demonstrated by [@5 HomePage ]handler&]
|
||||
[s5;i150;O0; Http`::Insert inserts a row to database, reading values
|
||||
of columns based on known (from .sch file) names of columns from
|
||||
equally named variables of shared variable space (which come
|
||||
from POST or GET request), as demonstrated by [@5 SubmitNew].&]
|
||||
[s5;i150;O0; Http`::Update updates a row in database, again based
|
||||
on names of columns and shared variable space, as demonstrated
|
||||
by [@5 SubmitEdit].&]
|
||||
[s5;i150;O0; It is also possible to add shared variables based on
|
||||
single row select, names being then same as names of columns,
|
||||
as demonstrated by [@5 Edit].&]
|
||||
[s5; &]
|
||||
[s7; #include <Skylark/Skylark.h>&]
|
||||
[s7; #include <plugin/sqlite3/Sqlite3.h>&]
|
||||
[s7; &]
|
||||
[s7; using namespace Upp;&]
|
||||
[s7; &]
|
||||
[s7; #define MODEL <Skylark09/myapp.sch>&]
|
||||
[s7; #define SCHEMADIALECT <plugin/sqlite3/Sqlite3Schema.h>&]
|
||||
[s7; #include <Sql/sch`_header.h>&]
|
||||
[s7; #include <Sql/sch`_schema.h>&]
|
||||
[s7; #include <Sql/sch`_source.h>&]
|
||||
[s7; &]
|
||||
[s7; SKYLARK(HomePage, `"`")&]
|
||||
[s7; `{&]
|
||||
[s7; /`*&]
|
||||
[s7; -|Sql sql;&]
|
||||
[s7; -|sql `* Select(ID, NAME, LASTNAME)&]
|
||||
[s7; -| .From(PERSON)&]
|
||||
[s7; -| .OrderBy(LASTNAME, NAME);&]
|
||||
[s7; -|ValueArray person;&]
|
||||
[s7; -|ValueMap vm;&]
|
||||
[s7; -|while(sql.Fetch(vm))&]
|
||||
[s7; -|-|person.Add(vm);&]
|
||||
[s7; `*/&]
|
||||
[s7; -|[* http(`"PERSON`", Select(SqlAll()).From(PERSON).OrderBy(LASTNAME,
|
||||
NAME))]&]
|
||||
[s7; -|.RenderResult(`"Skylark10/index`");&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; SKYLARK(SubmitNew, `"create/submit:POST`")&]
|
||||
[s7; `{&]
|
||||
[s7; /`*&]
|
||||
[s7; -|SQL `* Insert(PERSON)(NAME, http`[`"name`"`])(LASTNAME, http`[`"lastname`"`]);&]
|
||||
[s7; `*/&]
|
||||
[s7; -|[* SQL `* http.Insert(PERSON);]&]
|
||||
[s7; -|http.Redirect(HomePage);&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; SKYLARK(New, `"create`")&]
|
||||
[s7; `{&]
|
||||
[s7; -|http(`"ACTION`", SubmitNew)&]
|
||||
[s7; -|.RenderResult(`"Skylark10/Dialog`");&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; SKYLARK(SubmitEdit, `"edit/submit/`*:POST`")&]
|
||||
[s7; `{&]
|
||||
[s7; /`*&]
|
||||
[s7; -|SQL `* Update(PERSON)&]
|
||||
[s7; -|-|-|(NAME, http`[`"name`"`])&]
|
||||
[s7; -|-|-|(LASTNAME, http`[`"lastname`"`])&]
|
||||
[s7; -|-|-|.Where(ID `=`= http.Int(0));&]
|
||||
[s7; -|;&]
|
||||
[s7; `*/&]
|
||||
[s7; -|[* SQL `* http.Update(PERSON).Where(ID `=`= http.Int(0));]&]
|
||||
[s7; -|http.Redirect(HomePage);&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; SKYLARK(Edit, `"edit/`*`")&]
|
||||
[s7; `{&]
|
||||
[s7; -|int id `= http.Int(0);&]
|
||||
[s7; /`*&]
|
||||
[s7; -|Sql sql;&]
|
||||
[s7; -|sql `* Select(NAME, LASTNAME).From(PERSON).Where(ID `=`= id);&]
|
||||
[s7; -|if(!sql.Fetch()) `{&]
|
||||
[s7; -|-|http.Redirect(HomePage);&]
|
||||
[s7; -|-|return;&]
|
||||
[s7; -|`}&]
|
||||
[s7; -|http(`"NAME`", sql`[NAME`])(`"LASTNAME`", sql`[LASTNAME`]);&]
|
||||
[s7; `*/&]
|
||||
[s7; -|[* http]&]
|
||||
[s7; [* -|-|(Select(SqlAll()).From(PERSON).Where(ID `=`= id))]&]
|
||||
[s7; -|-|(`"ID`", id)&]
|
||||
[s7; -|-|(`"ACTION`", SubmitEdit, id)&]
|
||||
[s7; -|.RenderResult(`"Skylark10/Dialog`");&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; struct MyApp : SkylarkApp `{&]
|
||||
[s7; -|virtual void WorkThread();&]
|
||||
[s7; &]
|
||||
[s7; -|MyApp() `{&]
|
||||
[s7; -|-|root `= `"myapp`";&]
|
||||
[s7; -|-|threads `= 1; // Sqlite3 does not like threads...&]
|
||||
[s7; -|#ifdef `_DEBUG&]
|
||||
[s7; -|-|prefork `= 0;&]
|
||||
[s7; -|-|use`_caching `= false;&]
|
||||
[s7; -|#endif&]
|
||||
[s7; -|`}&]
|
||||
[s7; `};&]
|
||||
[s7; &]
|
||||
[s7; void InitModel()&]
|
||||
[s7; `{&]
|
||||
[s7; #ifdef `_DEBUG&]
|
||||
[s7; -|SqlSchema sch(SQLITE3);&]
|
||||
[s7; -|All`_Tables(sch);&]
|
||||
[s7; -|SqlPerformScript(sch.Upgrade());&]
|
||||
[s7; -|SqlPerformScript(sch.Attributes());&]
|
||||
[s7; -|sch.SaveNormal();&]
|
||||
[s7; #endif&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; void OpenSQL(Sqlite3Session`& sqlite3)&]
|
||||
[s7; `{&]
|
||||
[s7; -|if(!sqlite3.Open(ConfigFile(`"db`"))) `{&]
|
||||
[s7; -|-|LOG(`"Can`'t create or open database file`\n`");&]
|
||||
[s7; -|-|Exit(1);&]
|
||||
[s7; -|`}&]
|
||||
[s7; #ifdef `_DEBUG&]
|
||||
[s7; -|sqlite3.LogErrors();&]
|
||||
[s7; -|sqlite3.SetTrace();&]
|
||||
[s7; #endif&]
|
||||
[s7; -|SQL `= sqlite3;&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; void MyApp`::WorkThread()&]
|
||||
[s7; `{&]
|
||||
[s7; -|Sqlite3Session sqlite3;&]
|
||||
[s7; -|OpenSQL(sqlite3);&]
|
||||
[s7; -|RunThread();&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; void InitDB()&]
|
||||
[s7; `{&]
|
||||
[s7; -|Sqlite3Session sqlsession;&]
|
||||
[s7; -|OpenSQL(sqlsession);&]
|
||||
[s7; -|SqlSchema sch(SQLITE3);&]
|
||||
[s7; -|All`_Tables(sch);&]
|
||||
[s7; -|SqlPerformScript(sch.Upgrade());&]
|
||||
[s7; -|SqlPerformScript(sch.Attributes());&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; CONSOLE`_APP`_MAIN&]
|
||||
[s7; `{&]
|
||||
[s7; #ifdef `_DEBUG&]
|
||||
[s7; -|StdLogSetup(LOG`_FILE`|LOG`_COUT);&]
|
||||
[s7; -|Ini`::skylark`_log `= true;&]
|
||||
[s7; #endif&]
|
||||
[s7; &]
|
||||
[s7; -|InitDB();&]
|
||||
[s7; &]
|
||||
[s7; -|MyApp().Run();-|&]
|
||||
[s7; `}&]
|
||||
[s7; &]
|
||||
[s7; &]
|
||||
[s5; [* Skylark10/index.witz:]&]
|
||||
[s7; <html>&]
|
||||
[s7; <body>&]
|
||||
[s7; <table border`=`"1`">&]
|
||||
[s7; <tr>&]
|
||||
[s7; <th>No.</th>&]
|
||||
[s7; <th>First Name</th>&]
|
||||
[s7; <th>Last Name</th>&]
|
||||
[s7; </tr>&]
|
||||
[s7; `$for(i in PERSON)&]
|
||||
[s7; -|<tr>&]
|
||||
[s7; -| <td>`$(i.`_index `+ 1).</td>&]
|
||||
[s7; -| <td>`$i.NAME</td>&]
|
||||
[s7; -| <td>`$i.LASTNAME</td>&]
|
||||
[s7; -| <td><a href`=`$Edit(i.ID)>Edit</a></td>&]
|
||||
[s7; -|</tr>-|&]
|
||||
[s7; `$/&]
|
||||
[s7; </table>&]
|
||||
[s7; <a href`=`$New>Create new</a>&]
|
||||
[s7; </body>&]
|
||||
[s7; </html>&]
|
||||
[s7; &]
|
||||
[s7; &]
|
||||
[s5; [* Skylark10/dialog.witz:]&]
|
||||
[s7; <html>&]
|
||||
[s7; <body>&]
|
||||
[s7; <FORM action`=`$ACTION method`=`"post`" accept`-charset`=`"utf`-8`"
|
||||
enctype`=`"multipart/form`-data`">&]
|
||||
[s7; `$post`_identity()&]
|
||||
[s7; <P>&]
|
||||
[s7; First name: <INPUT type`=`"text`" name`=`"name`" value`=`"`$NAME`"><BR>&]
|
||||
[s7; Last name: <INPUT type`=`"text`" name`=`"lastname`" value`=`"`$LASTNAME`"><BR
|
||||
>&]
|
||||
[s7; <INPUT type`=`"submit`" value`=`"Send`" name`=`"OK`"/><BR>&]
|
||||
[s7; </P>&]
|
||||
[s7; </FORM>&]
|
||||
[s7; </table>&]
|
||||
[s7; </body>&]
|
||||
[s7; </html>&]
|
||||
[s7; &]
|
||||
[s7; &]
|
||||
[s5; [* Skylark10/myapp.sch:]&]
|
||||
[s7; TABLE`_(PERSON)&]
|
||||
[s7; -|INT`_ (ID) PRIMARY`_KEY AUTO`_INCREMENT&]
|
||||
[s7; -|STRING`_ (NAME, 200)&]
|
||||
[s7; -|STRING`_ (LASTNAME, 200)&]
|
||||
[s7; END`_TABLE&]
|
||||
[s7; &]
|
||||
[s7; &]
|
||||
[s7; ]]
|
||||
|
|
@ -17,6 +17,14 @@ void IdeFileIcon0(bool dir, const String& filename, Image& img)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if(ext == ".html")
|
||||
img = IdeCommonImg::html();
|
||||
if(ext == ".css")
|
||||
img = IdeCommonImg::css();
|
||||
if(ext == ".witz")
|
||||
img = IdeCommonImg::witz();
|
||||
if(ext == ".js")
|
||||
img = IdeCommonImg::js();
|
||||
if(ext == ".usc")
|
||||
img = IdeCommonImg::Script();
|
||||
if(ext == ".lng" || ext == ".lngj" || ext == ".t" || ext == ".jt")
|
||||
|
|
@ -89,12 +97,13 @@ void IdeFs(FileSel& fs) {
|
|||
}
|
||||
|
||||
void SourceFs(FileSel& fs) {
|
||||
String mask = "*.cpp *.h *.hpp *.c *.C *.cc *.cxx *.icpp *.lay *.iml *.lng *.sch *.usc *.rc *.brc *.upt";
|
||||
fs.Type("C++ files (*.cpp *.h *.hpp *.c *.C *.cc *.cxx *.icpp)", "*.cpp *.h *.hpp *.c *.C *.cc *.cxx *.icpp");
|
||||
fs.Type("Layout files (*.lay)", "*.lay");
|
||||
fs.Type("Image files (*.iml)", "*.iml");
|
||||
fs.Type("Language files (*.lng)", "*.lng");
|
||||
fs.Type("Web development files (*.html *.js *.css *.witz)", "*.html *.js *.css *.witz");
|
||||
fs.Type("Other special files (*.sch *.usc *.rc *.brc *.upt)", "*.sch *.usc *.rc *.brc *.upt");
|
||||
String mask = "*.cpp *.h *.hpp *.c *.C *.cc *.cxx *.icpp *.lay *.iml *.lng *.sch *.usc *.rc *.brc *.upt *.html *.js *.css *.witz";
|
||||
fs.Type("All source files (" + mask + ")", mask);
|
||||
IdeFs(fs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,62 +13,74 @@ IMAGE_ID(FFff)
|
|||
IMAGE_ID(Source)
|
||||
IMAGE_ID(Fast)
|
||||
IMAGE_ID(ISource)
|
||||
IMAGE_ID(js)
|
||||
IMAGE_ID(html)
|
||||
IMAGE_ID(css)
|
||||
IMAGE_ID(witz)
|
||||
IMAGE_ID(Script)
|
||||
IMAGE_ID(Images)
|
||||
IMAGE_ID(Language)
|
||||
IMAGE_ID(IncludePath)
|
||||
|
||||
IMAGE_BEGIN_DATA
|
||||
IMAGE_DATA(120,156,237,154,223,107,28,85,20,199,239,63,32,20,124,40,136,224,67,20,132,130,32,216,167,72,138,15,34,98,173,136)
|
||||
IMAGE_DATA(79,22,181,47,21,5,3,190,136,52,193,226,136,81,108,108,218,162,162,226,163,248,226,75,69,16,95,252,149,146,64,90)
|
||||
IMAGE_DATA(232,214,180,89,109,146,182,70,177,173,63,98,91,220,180,82,237,143,175,51,179,123,103,238,220,57,231,254,218,217,100,183)
|
||||
IMAGE_DATA(221,19,14,187,51,115,62,231,156,251,99,206,220,59,89,177,78,172,19,29,16,88,212,202,115,226,232,67,26,35,210,124)
|
||||
IMAGE_DATA(201,107,22,31,70,222,161,45,44,79,248,234,243,22,158,82,87,158,85,23,222,34,38,222,67,187,71,58,84,12,164,132)
|
||||
IMAGE_DATA(118,66,106,115,125,239,155,172,26,252,24,57,198,15,153,179,99,252,18,207,216,128,242,109,226,251,249,247,100,254,89,27)
|
||||
IMAGE_DATA(2,231,47,217,23,132,86,47,221,92,12,110,199,65,86,13,126,140,28,227,135,204,217,49,126,137,103,108,64,249,54,241)
|
||||
IMAGE_DATA(253,252,123,50,255,172,13,129,243,151,236,11,66,171,151,164,24,160,51,174,219,148,36,171,8,252,113,183,242,234,106,52)
|
||||
IMAGE_DATA(2,127,204,73,4,55,237,84,254,237,242,55,123,251,171,226,215,64,154,43,3,118,112,168,74,228,83,157,168,189,149,109)
|
||||
IMAGE_DATA(191,85,85,124,53,78,65,181,243,174,188,237,124,149,241,41,59,142,215,125,176,156,163,15,155,255,204,200,145,23,145,40)
|
||||
IMAGE_DATA(239,249,213,118,26,248,140,141,207,20,62,9,31,44,159,48,186,154,120,42,119,143,248,5,113,136,111,20,135,248,206,62)
|
||||
IMAGE_DATA(84,37,13,59,188,77,8,20,89,156,66,214,44,212,251,162,155,41,62,37,99,224,213,101,82,141,49,47,208,50,31,193)
|
||||
IMAGE_DATA(124,238,199,206,171,121,235,199,33,241,139,237,240,139,95,206,163,179,241,237,90,129,172,82,49,160,158,78,94,246,147,147)
|
||||
IMAGE_DATA(147,169,194,205,151,214,217,34,99,37,159,72,114,206,204,55,43,177,80,239,108,121,156,84,232,40,242,227,225,196,83,237)
|
||||
IMAGE_DATA(203,89,176,79,251,140,151,125,37,85,242,66,225,245,235,54,62,255,67,27,60,156,120,82,51,150,93,245,24,251,63,103)
|
||||
IMAGE_DATA(225,52,126,73,94,201,245,220,166,201,202,124,139,215,202,124,89,161,183,215,245,94,224,250,164,122,9,40,6,214,27,209)
|
||||
IMAGE_DATA(166,119,224,99,12,224,51,118,32,175,95,219,140,127,47,15,161,241,247,70,252,241,251,125,248,121,105,8,11,243,155,241)
|
||||
IMAGE_DATA(67,253,153,212,126,3,106,184,7,11,44,255,207,165,123,113,113,101,16,231,207,109,194,153,211,15,226,212,201,199,98,246)
|
||||
IMAGE_DATA(105,204,126,63,156,218,111,196,37,12,94,187,202,242,231,207,109,192,95,203,131,248,237,236,67,113,236,39,48,63,191,13)
|
||||
IMAGE_DATA(71,103,135,113,112,102,52,181,223,186,2,60,123,129,93,234,227,236,153,187,113,250,215,7,176,180,244,56,22,22,182,97)
|
||||
IMAGE_DATA(110,110,24,135,15,143,96,122,250,245,212,126,215,47,192,251,39,121,254,167,83,67,113,206,143,198,109,126,42,102,95,64)
|
||||
IMAGE_DATA(173,182,3,51,51,111,224,192,129,137,212,254,243,250,50,190,172,159,96,249,19,139,143,224,248,143,91,49,119,236,121,28)
|
||||
IMAGE_DATA(169,189,140,67,135,198,48,61,181,15,223,126,243,81,106,127,164,254,65,220,31,175,177,252,252,241,39,113,236,232,115,113)
|
||||
IMAGE_DATA(206,47,197,109,142,48,53,181,59,158,196,31,198,252,39,169,253,114,125,19,86,234,119,145,133,200,69,49,123,43,80,27)
|
||||
IMAGE_DATA(96,138,222,146,162,23,136,167,104,108,243,221,118,224,171,209,150,61,208,104,52,20,222,44,169,205,254,47,128,79,191,38)
|
||||
IMAGE_DATA(121,167,252,223,153,0,118,141,114,55,40,222,123,119,15,246,237,125,59,213,137,137,113,140,143,191,133,157,59,95,193,200)
|
||||
IMAGE_DATA(200,142,38,255,226,253,192,246,1,157,115,238,195,255,182,172,199,229,45,119,134,22,6,254,254,189,81,139,1,21,215,167)
|
||||
IMAGE_DATA(24,36,159,80,52,57,246,41,6,66,225,164,250,20,3,42,190,79,49,160,226,251,20,3,149,239,23,131,142,23,3,175)
|
||||
IMAGE_DATA(62,36,138,129,79,65,168,180,24,152,146,246,177,5,234,185,10,75,135,80,219,4,133,43,241,250,4,208,183,9,182,248)
|
||||
IMAGE_DATA(45,18,220,54,193,45,62,191,77,208,120,123,95,245,183,9,253,109,66,216,205,239,46,171,240,59,3,249,233,221,1,202)
|
||||
IMAGE_DATA(141,35,60,223,25,144,188,90,12,18,49,191,51,40,250,214,139,129,253,157,65,49,63,189,24,152,222,25,20,10,134,146)
|
||||
IMAGE_DATA(135,107,49,208,223,92,103,215,237,197,160,148,99,137,53,223,204,108,238,62,197,160,217,55,90,187,220,139,1,211,118,231)
|
||||
IMAGE_DATA(98,80,102,253,138,65,105,238,48,237,101,11,153,225,92,79,23,131,170,36,168,35,228,96,41,75,4,189,152,24,89,157)
|
||||
IMAGE_DATA(211,181,229,159,205,89,101,229,228,81,121,67,14,5,182,53,129,178,188,34,145,253,123,136,231,221,114,228,115,39,98,135)
|
||||
IMAGE_DATA(240,84,254,137,88,242,39,125,164,5,189,60,142,78,124,192,248,9,33,139,154,166,194,30,155,244,19,192,173,174,164,63)
|
||||
IMAGE_DATA(58,122,117,173,179,232,77,9,188,209,186,69,218,125,218,208,79,96,79,190,215,227,7,112,25,31,24,183,115,210,189,191)
|
||||
IMAGE_DATA(64,44,72,37,43,3,145,28,231,75,59,231,149,65,198,105,234,178,50,80,109,35,221,135,101,101,32,237,66,86,6,142)
|
||||
IMAGE_DATA(57,178,185,83,177,67,120,42,127,215,149,129,238,67,174,12,28,250,175,196,7,140,159,16,50,71,122,220,110,208,149,65)
|
||||
IMAGE_DATA(247,166,151,8,245,4,115,237,88,24,255,108,147,169,108,235,19,223,39,150,91,238,190,19,208,191,205,171,227,163,221,190)
|
||||
IMAGE_DATA(176,245,59,165,161,227,238,159,123,59,243,117,109,69,45,6,88,127,11,18,85,175,255,249,48,144,168,60,198,202,109,72)
|
||||
IMAGE_DATA(148,112,5,27,111,98,69,185,195,210,239,45,54,227,73,182,177,191,196,229,219,125,145,125,138,242,96,52,217,156,135,137)
|
||||
IMAGE_DATA(87,252,20,89,133,87,99,25,248,34,71,196,103,57,42,103,229,251,226,226,98,170,186,175,194,121,7,158,83,91,254,210)
|
||||
IMAGE_DATA(238,74,124,227,168,170,241,108,255,73,54,249,46,89,249,157,106,23,199,83,90,106,191,37,190,170,108,124,166,159,29,218)
|
||||
IMAGE_DATA(207,9,57,14,204,252,181,250,241,225,254,7,104,184,9,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
IMAGE_END_DATA(1408, 16)
|
||||
IMAGE_DATA(120,156,237,155,207,107,29,85,20,199,231,79,40,184,112,35,184,136,130,80,16,4,187,138,164,184,16,23,214,138,184,40)
|
||||
IMAGE_DATA(22,109,55,21,5,3,110,68,154,96,113,196,40,54,26,91,84,172,184,20,55,66,81,4,113,227,175,148,4,210,66,95)
|
||||
IMAGE_DATA(77,155,167,77,108,107,20,219,106,137,105,49,177,82,197,230,235,204,36,119,222,157,59,231,220,123,238,157,121,201,123,237)
|
||||
IMAGE_DATA(59,225,48,153,55,231,115,206,185,103,230,158,185,51,121,137,54,69,155,162,54,8,28,234,228,57,17,250,80,198,136,13)
|
||||
IMAGE_DATA(95,234,152,195,135,149,23,140,133,229,9,95,61,222,193,83,42,229,89,149,240,14,177,241,30,218,57,210,166,102,160,36)
|
||||
IMAGE_DATA(180,8,153,205,202,129,215,88,181,248,177,114,140,31,50,103,97,252,18,207,216,128,242,109,227,123,249,119,101,254,249,24)
|
||||
IMAGE_DATA(2,175,95,178,22,132,214,47,157,220,12,110,195,81,86,45,126,172,28,227,135,204,89,24,191,196,51,54,160,124,219,248)
|
||||
IMAGE_DATA(94,254,93,153,127,62,134,192,235,151,172,5,161,245,75,218,12,208,30,215,21,37,205,42,6,191,223,169,188,190,26,141)
|
||||
IMAGE_DATA(193,239,115,18,67,166,237,202,191,42,127,179,143,191,46,126,3,100,117,101,192,158,28,170,19,249,116,39,234,217,202,245)
|
||||
IMAGE_DATA(188,85,87,124,61,78,65,141,207,165,188,235,243,58,227,83,118,28,111,250,96,57,161,15,151,255,220,72,200,71,113,84)
|
||||
IMAGE_DATA(126,230,215,199,105,225,115,54,249,164,176,37,124,176,124,202,152,106,227,169,220,61,226,23,68,16,223,42,130,248,98,31)
|
||||
IMAGE_DATA(186,146,134,109,126,76,8,20,213,156,66,214,44,212,251,162,155,41,62,37,35,224,85,114,81,141,48,47,208,114,31,193)
|
||||
IMAGE_DATA(124,203,143,155,215,243,54,247,67,226,23,199,225,23,191,156,71,123,227,187,181,6,89,167,102,64,221,157,188,236,199,199)
|
||||
IMAGE_DATA(199,51,133,204,151,81,236,40,103,21,159,74,250,153,157,95,237,196,145,62,179,213,126,218,161,227,216,143,135,136,167,198)
|
||||
IMAGE_DATA(215,98,193,222,237,115,94,213,74,169,226,35,141,55,143,187,248,214,15,42,240,16,241,164,230,44,187,234,177,214,191,197)
|
||||
IMAGE_DATA(66,116,254,210,188,210,227,45,155,85,86,229,91,60,86,230,203,10,115,188,210,185,192,213,164,126,9,104,6,206,137,232)
|
||||
IMAGE_DATA(210,219,241,33,250,240,41,123,34,87,174,111,195,63,215,6,176,244,231,22,92,250,253,94,252,60,63,128,185,217,109,248)
|
||||
IMAGE_DATA(190,185,43,179,223,140,6,238,198,28,203,255,125,245,30,252,181,220,143,203,139,91,113,225,252,3,56,119,246,145,132,125)
|
||||
IMAGE_DATA(18,211,223,13,102,246,91,112,21,253,215,255,99,249,203,139,155,241,199,66,63,126,187,248,96,18,251,49,204,206,238,198)
|
||||
IMAGE_DATA(201,233,65,28,157,26,206,236,119,46,3,79,93,97,151,250,184,120,225,46,156,255,245,126,204,207,63,138,185,185,221,152)
|
||||
IMAGE_DATA(153,25,196,241,227,67,152,156,124,37,179,223,255,11,240,222,89,158,255,233,220,64,146,243,195,201,152,159,72,216,103,209)
|
||||
IMAGE_DATA(104,236,197,212,212,171,56,114,100,44,179,255,172,185,128,47,154,103,88,254,204,143,15,225,244,15,59,49,115,234,25,156)
|
||||
IMAGE_DATA(104,188,128,99,199,70,48,57,113,16,223,124,253,65,102,127,162,121,40,169,199,203,44,63,123,250,113,156,58,249,116,146)
|
||||
IMAGE_DATA(243,243,201,152,99,76,76,188,153,92,196,239,39,252,71,153,253,66,115,43,150,155,119,146,141,72,162,152,190,5,104,244)
|
||||
IMAGE_DATA(49,77,111,94,211,43,196,93,52,177,249,118,15,240,229,240,154,61,176,180,180,164,241,118,201,108,62,249,28,248,248,43)
|
||||
IMAGE_DATA(146,23,229,255,246,24,176,127,152,155,160,120,247,157,183,112,240,192,27,153,142,141,141,98,116,244,117,236,219,247,34,134)
|
||||
IMAGE_DATA(134,246,174,242,207,221,7,236,233,51,57,113,13,255,221,126,43,174,109,191,35,180,49,240,243,247,70,109,6,84,92,159)
|
||||
IMAGE_DATA(102,144,110,161,105,186,239,211,12,34,141,83,234,211,12,168,248,62,205,128,138,239,211,12,116,190,215,12,218,222,12,188)
|
||||
IMAGE_DATA(106,72,52,3,159,134,80,107,51,176,37,237,99,11,52,91,26,57,10,66,61,38,104,92,137,55,47,0,243,49,193,21)
|
||||
IMAGE_DATA(127,141,4,247,152,32,139,207,63,38,24,188,187,86,189,199,132,222,99,66,216,228,151,203,58,124,207,64,109,189,11,160)
|
||||
IMAGE_DATA(77,156,200,243,157,1,201,235,205,32,21,251,59,131,162,111,179,25,184,223,25,20,243,51,155,129,237,157,65,161,97,104)
|
||||
IMAGE_DATA(121,72,155,129,249,230,58,63,238,110,6,165,28,75,172,125,50,179,185,251,52,131,213,218,24,227,146,55,3,102,236,226)
|
||||
IMAGE_DATA(102,80,102,253,154,65,233,218,97,198,203,54,50,203,103,93,221,12,234,146,160,66,168,147,165,45,17,204,102,98,101,77)
|
||||
IMAGE_DATA(206,212,53,255,108,206,58,171,46,30,157,183,228,80,96,215,46,160,60,175,56,202,255,60,196,243,178,28,249,220,137,216)
|
||||
IMAGE_DATA(33,60,149,127,42,142,252,73,31,89,67,47,159,71,17,31,112,254,162,72,53,53,67,35,119,108,210,79,0,183,190,146)
|
||||
IMAGE_DATA(125,233,232,165,141,206,162,59,37,112,162,117,138,84,189,219,208,119,96,79,190,219,227,7,112,57,31,24,183,125,210,185)
|
||||
IMAGE_DATA(223,64,44,72,45,43,131,40,221,111,45,237,196,43,131,156,51,84,178,50,208,109,99,211,135,99,101,160,236,66,86,6)
|
||||
IMAGE_DATA(194,28,217,220,169,216,33,60,149,191,116,101,96,250,80,43,3,65,253,74,124,192,249,139,34,149,35,125,222,110,204,149)
|
||||
IMAGE_DATA(129,135,84,25,8,176,18,92,140,140,85,234,233,163,192,122,250,32,89,161,143,146,173,193,217,124,144,177,76,63,76,30)
|
||||
IMAGE_DATA(108,174,212,239,82,31,130,241,144,99,224,242,118,140,159,244,33,172,157,179,150,85,175,33,79,182,224,35,144,205,125,84)
|
||||
IMAGE_DATA(96,221,178,65,255,194,236,236,200,54,17,248,112,242,154,159,42,241,249,137,32,20,27,159,126,151,221,220,42,149,242,101)
|
||||
IMAGE_DATA(251,214,239,190,241,125,249,58,198,127,248,240,37,50,15,41,191,99,199,98,37,222,220,250,212,191,202,248,61,181,22,249)
|
||||
IMAGE_DATA(31,114,29,133,141,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
IMAGE_END_DATA(1376, 16)
|
||||
|
||||
IMAGE_BEGIN_DATA
|
||||
IMAGE_DATA(120,156,237,148,97,10,128,48,8,133,61,194,238,213,133,186,189,181,31,110,42,110,234,42,40,232,193,35,130,190,167,115)
|
||||
IMAGE_DATA(18,20,40,128,8,36,12,122,36,60,179,112,219,177,63,1,132,61,190,50,220,90,79,215,87,223,101,103,33,250,236,103)
|
||||
IMAGE_DATA(144,61,145,77,158,213,183,24,254,110,241,220,154,213,25,222,44,84,157,133,89,244,58,214,93,58,247,218,122,149,179,140)
|
||||
IMAGE_DATA(243,220,179,157,138,236,149,224,213,78,101,246,218,98,163,252,136,141,240,33,215,159,193,75,53,59,156,203,210,18,173,178)
|
||||
IMAGE_DATA(228,100,134,96,239,200,72,178,34,99,145,109,25,23,216,95,31,212,1,40,156,179,185,0,0,0,0,0,0,0,0,0)
|
||||
IMAGE_END_DATA(160, 2)
|
||||
IMAGE_DATA(120,156,237,152,75,78,196,48,12,134,115,1,164,217,33,113,35,196,133,88,246,68,28,168,71,96,9,75,22,30,50,144)
|
||||
IMAGE_DATA(214,118,253,76,59,165,149,240,232,87,211,105,62,219,113,83,79,53,229,82,46,229,14,6,1,153,188,101,1,31,46,143)
|
||||
IMAGE_DATA(252,172,137,175,249,48,121,193,151,202,151,193,30,91,188,199,238,201,175,205,191,135,39,243,58,242,143,152,198,39,117,12)
|
||||
IMAGE_DATA(251,163,102,224,242,78,241,187,155,73,187,230,248,136,196,239,110,38,206,70,154,248,82,6,133,27,118,225,233,92,122,60)
|
||||
IMAGE_DATA(11,175,177,25,94,51,139,79,232,56,86,155,1,28,43,37,110,171,222,48,204,143,211,16,132,185,153,248,153,88,177,220)
|
||||
IMAGE_DATA(115,62,122,214,188,143,143,181,181,240,234,46,169,247,190,231,115,63,207,195,207,13,55,3,120,124,128,42,124,253,253,25)
|
||||
IMAGE_DATA(160,170,157,195,231,19,84,9,174,192,227,45,182,44,11,118,27,255,178,19,47,178,31,111,11,14,119,111,212,197,57,255)
|
||||
IMAGE_DATA(195,206,60,88,60,251,53,152,89,196,227,88,6,79,57,33,190,202,73,57,163,241,56,142,55,113,95,228,251,0,175,201)
|
||||
IMAGE_DATA(203,191,205,251,250,126,112,176,24,175,214,175,177,117,220,216,54,150,214,165,241,146,22,235,119,226,99,169,241,149,58,7)
|
||||
IMAGE_DATA(214,175,153,120,31,148,253,235,250,73,113,236,205,192,93,172,227,184,110,91,120,121,133,249,88,10,145,199,87,6,43,241)
|
||||
IMAGE_DATA(106,182,73,124,54,47,91,11,146,231,188,6,154,83,147,200,163,248,18,131,207,37,30,139,179,220,135,87,11,22,167,163)
|
||||
IMAGE_DATA(22,115,28,233,94,58,247,117,202,149,214,50,206,99,89,123,42,178,175,8,207,246,84,102,95,75,108,148,215,216,8,31)
|
||||
IMAGE_DATA(210,157,254,51,216,194,50,93,112,193,2,184,5,50,217,166,164,15,194,110,225,35,201,18,31,157,236,228,99,5,251,111)
|
||||
IMAGE_DATA(39,180,43,210,170,244,249,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
IMAGE_END_DATA(448, 6)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue