From: konrad Date: Sun, 15 Mar 2009 15:29:01 +0000 (+0000) Subject: more on client side transactions X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=4adfb07011134ab399110cac551735b0c5cba8a1;p=konrad%2Fsmoke.git more on client side transactions git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@278 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- diff --git a/src/wbase/WInterface.cpp b/src/wbase/WInterface.cpp new file mode 100644 index 0000000..4eb4f3a --- /dev/null +++ b/src/wbase/WInterface.cpp @@ -0,0 +1,47 @@ +// +// C++ Implementation: WInterface +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2009 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#include "WInterface.h" + +#include +#include + +QMap WInterface::inst; + +static QMutex mtx; + +WInterface*WInterface::instance(QString name) +{ + QMutexLocker ml(&mtx); + if(inst.contains(name))return inst[name]; + else return 0; +} + +WInterface::WInterface(QString name) +{ + m_proxyport=0; + m_wtimeout=30; + QMutexLocker ml(&mtx); + if(inst.contains(name)){ + delete inst[name]; + } + inst.insert(name,this); +} + +WInterface::~WInterface() +{ +} + +QMap WInterface::headers(QString)const +{ + return QMap(); +} diff --git a/src/wbase/WInterface.h b/src/wbase/WInterface.h new file mode 100644 index 0000000..5bfe746 --- /dev/null +++ b/src/wbase/WInterface.h @@ -0,0 +1,68 @@ +// +// C++ Interface: WInterface +// +// Description: +// +// +// Author: Konrad Rosenbaum , (C) 2009 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef WOB_INTERFACE_H +#define WOB_INTERFACE_H + +#include +#include +#include + +class WInterface:public QObject +{ + protected: + WInterface(QString name); + + public: + virtual ~WInterface(); + /**overwrite if you need additional headers (eg. session-ids) for certain transactions (transaction name is handed in as string argument); per default returns empty map*/ + virtual QMap headers(QString)const; + + /**returns the URL of the interface*/ + QUrl url()const{return m_url;} + /**sets the URL of the interface*/ + void setUrl(QUrl u){m_url=u;} + + /**returns whether the interface uses a proxy*/ + bool useProxy()const{return m_proxyhost!="";} + /**returns whether the proxy needs authentication*/ + bool useProxyAuth()const{return m_proxyuser!="";} + /**resets the proxy settings to no proxy use*/ + void resetProxy(){m_proxyhost="";m_proxyport=0;m_proxyuser="";m_proxypass="";} + /**sets the proxy settings*/ + void setProxy(QString proxyhost,unsigned short proxyport,QString proxyuser="",QString proxypassword=""){m_proxyhost=proxyhost;m_proxyport=proxyport;m_proxyuser=proxyuser;m_proxypass=proxypassword;} + /**returns the proxy host name*/ + QString proxyHost()const{return m_proxyhost;} + /**returns the proxy port*/ + unsigned short proxyPort()const{return m_proxyport;} + /**returns the proxy user name*/ + QString proxyUser()const{return m_proxyuser;} + /**returns the proxy password*/ + QString proxyPassword()const{return m_proxypass;} + + /**return timeout in seconds*/ + int webTimeout()const{return m_wtimeout;} + /**set timeout for page loads in seconds*/ + void setWebTimeout(int t){if(t>0)m_wtimeout=t;} + + /**returns the instance registered under that name*/ + static WInterface*instance(QString); + + private: + static QMapinst; + QUrl m_url; + QString m_proxyhost,m_proxyuser,m_proxypass; + unsigned short m_proxyport; + int m_wtimeout; +}; + +#endif diff --git a/src/wbase/WTransaction.cpp b/src/wbase/WTransaction.cpp index 926ba37..f5f2eba 100644 --- a/src/wbase/WTransaction.cpp +++ b/src/wbase/WTransaction.cpp @@ -9,3 +9,155 @@ // Copyright: See README/COPYING files that come with this distribution // // + +#include "WTransaction.h" +#include "WInterface.h" + +//WaitCursor, TODO: refactor this +#include "main.h" + +#include +#include +#include +#include +#include + +WTransaction::WTransaction(QString ifc) +{ + m_haserror=false; + m_httpid=-1; + m_iface=ifc; +} +WTransaction::WTransaction(const WTransaction&t) + :QObject() +{ + m_haserror=t.m_haserror; + m_errstr=t.m_errstr; + m_errtype=t.m_errtype; + m_iface=t.m_iface; + m_httpid=-1; +} + +static inline QString esc(const QByteArray ar) +{ + QString r; + for(int i=0;i=32 && a<=127))r+=(char)a; + else r+="\\x"+QByteArray((char*)&a,1).toHex(); + } + return r; +} + +QByteArray WTransaction::executeQuery(QString hreq,QByteArray data) +{ + QHttp req; + connect(&req,SIGNAL(requestFinished(int,bool)),this,SLOT(webReady(int,bool))); + //show the user we are waiting + WaitCursor wc; + //set up request + QString log; + QEventLoop loop(this); + connect(this,SIGNAL(webFinished()),&loop,SLOT(quit())); + WInterface *iface=WInterface::instance(m_iface); + if(!iface){ + qDebug("Error: transaction cannot find interface."); + m_haserror=true; + m_errtype="_iface"; + return QByteArray(); + } + QUrl url=iface->url(); + int port=url.port(); + if(port<=0){ + if(url.scheme().toLower()=="http")port=80; + else port=443; + } + qDebug()<useProxy())req.setProxy(iface->proxyHost(),iface->proxyPort(),iface->proxyUser(),iface->proxyPassword()); + QString pathspec=url.path(); + if(pathspec=="")pathspec="/"; + if(url.encodedQuery()!="")pathspec+="?"+url.encodedQuery(); + QHttpRequestHeader hrh("POST",pathspec); + QString hostspec=url.host(); + if(url.port()>0)hostspec+=":"+QString::number(port); + hrh.setValue("Host",hostspec); + hrh.setValue("X-Wob-Request",hreq); + //TODO: hrh.setValue("X-MagicSmoke-Session",sessionid); + hrh.setContentLength(data.size()); + hrh.setContentType("application/x-webobject; charset=UTF-8"); + m_httpid=req.request(hrh,data); + //if(loglvl>LogMinimal) + log=QString("Request %3 with header:\n%1\n\nRequest Body:\n%2\n<---->\n").arg(hrh.toString()).arg(esc(data)).arg(m_httpid); + qDebug("started req %i",m_httpid); + //start loop + QTimer::singleShot(iface->webTimeout()*1000,this,SLOT(webTimeout())); + loop.exec(); + m_httpid=-1; + //process result + if(m_haserror && m_errtype=="_timeout"){ + //it did not finish yet, caught a timeout. + req.abort(); + m_errstr="Web Request timed out."; + qDebug("Request %i timed out.",m_httpid); + //TODO: if(loglvl&LogOnError) + qDebug()<\nHTTP Response %3 Headers:\n%1\nHTTP Response %3 Body:\n%2\n<------------------").arg(rsph.toString()).arg(esc(rspdata)).arg(m_httpid); + qDebug()< #include +#include #include "nullable.h" class WTransaction:public QObject { + Q_OBJECT + public: + bool hasError()const{return m_haserror;} + QString errorType()const{return m_errtype;} + QString errorString()const{return m_errstr;} protected: - WTransaction(){} - WTransaction(const WTransaction&){} + WTransaction(QString iface=QString()); + WTransaction(const WTransaction&); + + QByteArray executeQuery(QString,QByteArray); + private slots: + void webTimeout(); + void webReady(int,bool); + signals: + void webFinished(); + private: + bool m_haserror; + QString m_errtype,m_errstr,m_iface; + int m_httpid; }; #endif diff --git a/src/wbase/wbase.pri b/src/wbase/wbase.pri index 90988ba..389787b 100644 --- a/src/wbase/wbase.pri +++ b/src/wbase/wbase.pri @@ -1,10 +1,12 @@ HEADERS += \ wbase/nullable.h \ wbase/WObject.h \ - wbase/WTransaction.h + wbase/WTransaction.h \ + wbase/WInterface.h SOURCES += \ wbase/WObject.cpp \ - wbase/WTransaction.cpp + wbase/WTransaction.cpp \ + wbase/WInterface.cpp INCLUDEPATH += ./wbase ./wob \ No newline at end of file diff --git a/wob/magicsmoke.wolf b/wob/magicsmoke.wolf index 895aa5e..46e7b4c 100644 --- a/wob/magicsmoke.wolf +++ b/wob/magicsmoke.wolf @@ -8,12 +8,12 @@ --> - + - + diff --git a/woc/processor.cpp b/woc/processor.cpp index 095c2fe..fff55db 100644 --- a/woc/processor.cpp +++ b/woc/processor.cpp @@ -38,6 +38,7 @@ WocProcessor::WocProcessor() m_dbInst="dbInst"; m_dbSchema="dbSchema"; m_error=false; + m_projname="WobProject"; inst=this; } @@ -105,6 +106,8 @@ bool WocProcessor::processFile(QString fn) m_baseDir=el.attribute("baseDir"); if(el.hasAttribute("wobDir")) m_wobDir=el.attribute("wobDir"); + if(el.hasAttribute("name")) + m_projname=el.attribute("name"); }else if(tn=="Include"){ if(!processFile(m_baseDir+"/"+m_wobDir+"/"+el.attribute("file"))) @@ -119,7 +122,7 @@ bool WocProcessor::processFile(QString fn) m_dbVer=el.attribute("version"); }else if(tn=="QtClientOutput"){ - new WocQtClientOut(el.attribute("sourceDir","."), el.attribute("subDir","qtwob"), el.attribute("priInclude","qtwob.pri"),str2bool(el.attribute("clean","0"))); + new WocQtClientOut(el); if(m_error)return false; }else if(tn=="PHPServerOutput"){ diff --git a/woc/processor.h b/woc/processor.h index 60dee66..209cc9b 100644 --- a/woc/processor.h +++ b/woc/processor.h @@ -312,6 +312,8 @@ class WocProcessor:public QObject QString baseDir()const{return m_baseDir;} /**returns the directory where WOLFs are found, should normally not be used outside this class*/ QString wobDir()const{return m_wobDir;} + /**returns the project name (default="WobProject")*/ + QString projectName()const{return m_projname;} /**returns the current communication protocol version*/ QString verComm()const{return m_verComm;} /**returns the communication protocol version that is at least needed to be compatible*/ @@ -342,7 +344,7 @@ class WocProcessor:public QObject private slots: void errorFound(); private: - QString m_baseDir,m_wobDir,m_verComm,m_verNeedComm,m_verHR; + QString m_baseDir,m_wobDir,m_verComm,m_verNeedComm,m_verHR,m_projname; QString m_svnTarget,m_svnRev,m_svnExe,m_dbInst,m_dbSchema,m_dbVer; bool m_error; diff --git a/woc/qtout.cpp b/woc/qtout.cpp index 86401b2..f5965e0 100644 --- a/woc/qtout.cpp +++ b/woc/qtout.cpp @@ -13,12 +13,35 @@ #include "qtout.h" #include +#include -WocQtClientOut::WocQtClientOut(QString srcDir,QString subDir,QString prifile,bool clean) +//start section of all header files +static const QByteArray HDRSTART= + "//AUTOMATICALLY GENERATED FILE\n" + "//DO NOT EDIT THIS FILE DIRECTLY, USE THE XML SOURCE!\n" + "#ifndef WOBGEN_%\n" + "#define WOBGEN_%\n\n"; +//end section of all header files +static const QByteArray HDREND="\n//END OF AUTOMATICALLY GENERATED FILE\n#endif\n"; + +//start section of all source files +static const QByteArray SRCSTART= + "//AUTOMATICALLY GENERATED FILE\n" + "//DO NOT EDIT THIS FILE DIRECTLY, USE THE XML SOURCE!\n" + "#include \"%.h\"\n" + "#include \n" + "#include \n" + "#include \n"; +//end section of all source files +static const QByteArray SRCEND="\n//END OF AUTOMATICALLY GENERATED FILE\n"; + +WocQtClientOut::WocQtClientOut(QDomElement&el) { qDebug("Info: creating Qt Client Output Generator."); - m_basedir=WocProcessor::instance()->baseDir()+"/"+srcDir; - m_subdir=subDir; + m_basedir=WocProcessor::instance()->baseDir()+"/"+el.attribute("sourceDir","."); + m_subdir=el.attribute("subDir","qtwob"); + bool clean=str2bool(el.attribute("clean","0")); + m_prefix=el.attribute("classPrefix","Wob"); //cleanup directory (remove normal files, assume remainder is harmless) QDir d(m_basedir+"/"+m_subdir); if(d.exists() && clean){ @@ -28,46 +51,59 @@ WocQtClientOut::WocQtClientOut(QString srcDir,QString subDir,QString prifile,boo } //get/create directory if(!d.exists())QDir(".").mkpath(m_basedir+"/"+m_subdir); + //create project file - m_pri.setFileName(m_basedir+"/"+m_subdir+"/"+prifile); + m_pri.setFileName(m_basedir+"/"+m_subdir+"/"+el.attribute("priInclude","qtwob.pri")); if(!m_pri.open(QIODevice::WriteOnly|QIODevice::Truncate)){ qDebug("Error: cannot create Qt project file %s.",m_pri.fileName().toAscii().data()); emit errorFound(); return; } m_pri.write(QByteArray("#AUTOMATICALLY GENERATED FILE - DONT CHANGE!\n")); + + //create interface class + QString pn=WocProcessor::instance()->projectName(); + m_iface.setFileName(m_basedir+"/"+m_subdir+"/"+m_prefix+"Interface.h"); + if(!m_iface.open(QIODevice::WriteOnly|QIODevice::Truncate)){ + qDebug("Error: cannot create Qt interface file %s.",m_iface.fileName().toAscii().data()); + emit errorFound(); + return; + } + m_iface.write(QByteArray(HDRSTART).replace("%",m_prefix.toAscii()+"INTERFACE_H")); + m_iface.write(QByteArray("#include \""+m_prefix.toAscii()+"Include.h\"\n#include \"WInterface.h\"\n")); + m_iface.write(QString("class "+m_prefix+"Interface:public WInterface\n{\n").toAscii()); + m_iface.write(QString(" public:\n "+m_prefix+"Interface(QString name=\""+pn+"\"):WInterface(name){}\n").toAscii()); + m_iface.write(QString(" static "+pn+"Interface*instance(QString name=\""+pn+"\"){qobject_cast<"+m_prefix+"Interface*>(WInterface::instance(name));}\n").toAscii()); + + //create all includer + m_hdr.setFileName(m_basedir+"/"+m_subdir+"/"+m_prefix+"Include.h"); + if(!m_hdr.open(QIODevice::WriteOnly|QIODevice::Truncate)){ + qDebug("Error: cannot create Qt header file %s.",m_hdr.fileName().toAscii().data()); + emit errorFound(); + return; + } + m_hdr.write(QByteArray(HDRSTART).replace("%",m_prefix.toAscii()+"INCLUDE_H")); + m_hdr.write(QByteArray("#include \""+m_prefix.toAscii()+"Interface.h\"\n")); + } WocQtClientOut::~WocQtClientOut(){} void WocQtClientOut::finalize() { + m_iface.write(QByteArray("};\n")+HDREND); + m_iface.close(); + m_pri.write(QByteArray("\n#END OF AUTOGENERATED PRI FILE\n")); m_pri.close(); + m_hdr.write(HDREND); + m_hdr.close(); } void WocQtClientOut::newTable(const WocTable&){/*not needed, Qt client is a few levels higher*/} -//start section of all header files -static const QByteArray HDRSTART= - "//AUTOMATICALLY GENERATED FILE\n" - "#ifndef WOBGEN_%\n" - "#define WOBGEN_%\n\n"; -//end section of all header files -static const QByteArray HDREND="\n//END OF FILE\n#endif\n"; - -//start section of all source files -static const QByteArray SRCSTART= - "//AUTOMATICALLY GENERATED FILE\n" - "#include \"%.h\"\n" - "#include \n" - "#include \n" - "#include \n"; -//end section of all source files -static const QByteArray SRCEND="\n//END OF FILE\n"; - void WocQtClientOut::newClass(const WocClass&cls) { - QString cn="WO"+cls.name(); + QString cn=m_prefix+"O"+cls.name(); QString cna=cn; if(cls.isAbstract())cna+="Abstract"; addFile(cna); @@ -90,7 +126,7 @@ void WocQtClientOut::newClass(const WocClass&cls) QStringList k=cls.propertyNames(); for(int i=0;iprojectName()+"\""; + hcd="\t"+cn+"("+inlist+defparm+");\n"; + scd+=cn+"::"+cn+"("+inlist+")\n\t:WTransaction(iface)\n{\n"; for(int i=0;i +class QDomElement; + class WocQtClientOut:public WocOutput { public: - WocQtClientOut(QString srcDir,QString subDir,QString prifile,bool clean); + WocQtClientOut(QDomElement&); ~WocQtClientOut(); protected: virtual void finalize(); @@ -28,8 +30,8 @@ class WocQtClientOut:public WocOutput virtual void newTable(const WocTable&); virtual void newTransaction(const WocTransaction&); private: - QString m_basedir,m_subdir; - QFile m_pri; + QString m_basedir,m_subdir,m_prefix; + QFile m_pri,m_iface,m_hdr; /**helper: adds a file to the project file*/ void addFile(QString basename);