Beaming Scene Service  2.0
RakNet wrapper for managing data communications between multiple Beaming clients
netClient/PHPConnections.cpp
Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 #include "PHPConnections.h"
00018 #include "HTTPConnection.h"
00019 #include "RakSleep.h"
00020 #include "RakString.h"
00021 #include "RakNetTypes.h"
00022 #include "GetTime.h"
00023 #include "RakAssert.h"
00024 #include <cstring>
00025 #include <cstdlib>
00026 #include <cstdio>
00027 #include "Itoa.h"
00028 
00029 
00030 
00031 // Column with this header contains the name of the client, passed to UploadTable()
00032 static const char *CLIENT_NAME_COMMAND="__CLIENT_NAME";
00033 // Column with this header contains the port of the client, passed to UploadTable()
00034 static const char *CLIENT_PORT_COMMAND="__CLIENT_PORT";
00035 // Column with this header contains the IP address of the client, passed to UploadTable()
00036 static const char *SYSTEM_ADDRESS_COMMAND="_System_Address";
00037 // Returned from the PHP server indicating when this row was last updated.
00038 static const char *LAST_UPDATE_COMMAND="__SEC_AFTER_EPOCH_SINCE_LAST_UPDATE";
00039 
00040 using namespace RakNet;
00041 using namespace DataStructures;
00042 
00043 PHPConnections::PHPConnections()
00044     : nextRepost(0)
00045 {
00046     Map<RakString, RakString>::IMPLEMENT_DEFAULT_COMPARISON();
00047 }
00048 PHPConnections::~PHPConnections()
00049 {
00050 }
00051 void PHPConnections::Init(HTTPConnection *_http, const char *_path)
00052 {
00053         http=_http;
00054         pathToPHP=_path;
00055 }
00056 
00057 void PHPConnections::SetField( RakNet::RakString columnName, RakNet::RakString value )
00058 {
00059         if (columnName.IsEmpty())
00060                 return;
00061 
00062         if (columnName==CLIENT_NAME_COMMAND ||
00063                 columnName==CLIENT_PORT_COMMAND ||
00064                 columnName==LAST_UPDATE_COMMAND)
00065         {
00066                 RakAssert("PHPConnections::SetField attempted to set reserved column name" && 0);
00067                 return;
00068         }
00069 
00070     fields.Set(columnName, value);
00071 }
00072 unsigned int PHPConnections::GetFieldCount(void) const
00073 {
00074         return fields.Size();
00075 }
00076 void PHPConnections::GetField(unsigned int index, RakNet::RakString &columnName, RakNet::RakString &value)
00077 {
00078         RakAssert(index < fields.Size());
00079         columnName=fields.GetKeyAtIndex(index);
00080         value=fields[index];
00081 }
00082 void PHPConnections::SetFields(DataStructures::Table *table)
00083 {
00084         ClearFields();
00085 
00086         unsigned columnIndex, rowIndex;
00087         DataStructures::Table::Row *row;
00088         
00089         for (rowIndex=0; rowIndex < table->GetRowCount(); rowIndex++)
00090         {
00091                 row = table->GetRowByIndex(rowIndex, 0);
00092                 for (columnIndex=0; columnIndex < table->GetColumnCount(); columnIndex++)
00093                 {
00094                         SetField( table->ColumnName(columnIndex), row->cells[columnIndex]->ToString(table->GetColumnType(columnIndex)) );
00095                 }
00096         }
00097 }
00098 
00099 void PHPConnections::ClearFields(void)
00100 {
00101         fields.Clear();
00102         nextRepost=0;
00103 }
00104 
00105 void PHPConnections::UploadTable(RakNet::RakString uploadPassword, RakNet::RakString clientName, unsigned short clientPort, bool autoRepost)
00106 {
00107         clientNameParam=clientName;
00108         clientPortParam=clientPort;
00109         currentOperation="";
00110         currentOperation="?query=upload&uploadPassword=";
00111         currentOperation+=uploadPassword;
00112         SendOperation();
00113 
00114         if (autoRepost)
00115                 nextRepost=RakNet::GetTimeMS()+50000;
00116         else
00117                 nextRepost=0;
00118 }
00119 void PHPConnections::DownloadTable(RakNet::RakString downloadPassword)
00120 {
00121         currentOperation="?query=download&downloadPassword=";
00122         currentOperation+=downloadPassword;
00123         SendOperation();
00124 }
00125 void PHPConnections::UploadAndDownloadTable(RakNet::RakString uploadPassword, RakNet::RakString downloadPassword, RakNet::RakString clientName, unsigned short clientPort, bool autoRepost)
00126 {
00127         clientNameParam=clientName;
00128         clientPortParam=clientPort;
00129         currentOperation="?query=upDown&downloadPassword=";
00130         currentOperation+=downloadPassword;
00131         currentOperation+="&uploadPassword=";
00132         currentOperation+=uploadPassword;
00133 
00134         SendOperation();
00135 
00136         if (autoRepost)
00137                 nextRepost=RakNet::GetTimeMS()+50000;
00138         else
00139                 nextRepost=0;
00140 }
00141 
00142 HTTPReadResult PHPConnections::ProcessHTTPRead(RakNet::RakString httpRead)
00143 {
00144         const char *c = (const char*) httpRead.C_String(); // current position
00145         HTTPReadResult resultCode=HTTP_RESULT_EMPTY;
00146 
00147         lastDownloadedTable.Clear();
00148 
00149 
00150         if (*c=='\n')
00151                 c++;
00152         char buff[256];
00153         int buffIndex;
00154         bool isCommand=true;
00155         DataStructures::List<RakNet::RakString> columns;
00156         DataStructures::List<RakNet::RakString> values;
00157         RakNet::RakString curString;
00158         bool isComment=false;
00159         buffIndex=0;
00160         while(c && *c)
00161         {
00162                 // 3 is comment
00163                 if (*c=='\003')
00164                 {
00165                         isComment=!isComment;
00166                         c++;
00167                         continue;
00168                 }
00169                 if (isComment)
00170                 {
00171                         c++;
00172                         continue;
00173                 }
00174 
00175                 // 1 or 2 separates fields
00176                 // 4 separates rows
00177                 if (*c=='\001')
00178                 {
00179                         if (isCommand)
00180                         {
00181                                 buff[buffIndex]=0;
00182                                 columns.Push(RakString::NonVariadic(buff), __FILE__, __LINE__);
00183                                 isCommand=false;
00184                                 if (buff[0]!=0)
00185                                         resultCode=HTTP_RESULT_GOT_TABLE;
00186                         }
00187                         else
00188                         {
00189                                 buff[buffIndex]=0;
00190                                 values.Push(RakString::NonVariadic(buff), __FILE__, __LINE__);
00191                                 isCommand=true;
00192                         }
00193                         buffIndex=0;
00194                 }
00195                 else if (*c=='\002')
00196                 {
00197                         buff[buffIndex]=0;
00198                         buffIndex=0;
00199                         values.Push(RakString::NonVariadic(buff), __FILE__, __LINE__);
00200                         isCommand=true;
00201                         PushColumnsAndValues(columns, values);
00202                         columns.Clear(true, __FILE__, __LINE__);
00203                         values.Clear(true, __FILE__, __LINE__);
00204 
00205                 }
00206                 else
00207                 {
00208                         if (buffIndex<256-1)
00209                                 buff[buffIndex++]=*c;
00210                 }
00211                 c++;
00212         }
00213         if (buff[0] && columns.Size()==values.Size()+1)
00214         {
00215                 buff[buffIndex]=0;
00216                 values.Push(RakString::NonVariadic(buff), __FILE__, __LINE__);
00217         }
00218 
00219         PushColumnsAndValues(columns, values);
00220 
00221         return resultCode;
00222 }
00223 void PHPConnections::PushColumnsAndValues(DataStructures::List<RakNet::RakString> &columns, DataStructures::List<RakNet::RakString> &values)
00224 {
00225         DataStructures::Table::Row *row=0;
00226 
00227         unsigned int i;
00228         for (i=0; i < columns.Size() && i < values.Size(); i++)
00229         {
00230                 if (columns[i].IsEmpty()==false)
00231                 {
00232                         unsigned col = lastDownloadedTable.ColumnIndex(columns[i]);
00233                         if(col == (unsigned)-1)
00234                         {
00235                                 col = lastDownloadedTable.AddColumn(columns[i], DataStructures::Table::STRING);
00236                         }
00237 
00238                         if (row==0)
00239                         {
00240                                 row = lastDownloadedTable.AddRow(lastDownloadedTable.GetAvailableRowId());
00241                         }
00242                         row->UpdateCell(col,values[i].C_String());
00243                 }
00244         }
00245 }
00246 const DataStructures::Table *PHPConnections::GetLastDownloadedTable(void) const
00247 {
00248         return &lastDownloadedTable;
00249 }
00250 void PHPConnections::SendOperation(void)
00251 {
00252         RakString outgoingMessageBody;
00253         char buff[64];
00254 
00255         outgoingMessageBody += CLIENT_PORT_COMMAND;
00256         outgoingMessageBody += '\001';
00257         outgoingMessageBody += Itoa(clientPortParam,buff,10);
00258         outgoingMessageBody += '\001';
00259         outgoingMessageBody += CLIENT_NAME_COMMAND;
00260         outgoingMessageBody += '\001';
00261         outgoingMessageBody += clientNameParam;
00262 
00263         for (unsigned i = 0; i < fields.Size(); i++)
00264         {
00265                 RakString value = fields[i];
00266                 value.URLEncode();
00267                 outgoingMessageBody += RakString("\001%s\001%s",
00268                         fields.GetKeyAtIndex(i).C_String(),
00269                         value.C_String());
00270         }
00271 
00272         RakString postURL;
00273         postURL+=pathToPHP;
00274         postURL+=currentOperation;
00275         http->Post(postURL.C_String(), outgoingMessageBody, "application/x-www-form-urlencoded");
00276 
00277 }
00278 void PHPConnections::Update(void)
00279 {
00280         if (http->IsBusy())
00281                 return;
00282 
00283 
00284         if (nextRepost==0 || fields.Size()==0)
00285                 return;
00286 
00287         RakNetTimeMS time = GetTimeMS();
00288 
00289         // Entry deletes itself after 60 seconds, so keep reposting if set to do so
00290         if (time > nextRepost)
00291         {
00292                 nextRepost=RakNet::GetTimeMS()+50000;
00293                 SendOperation();
00294         }
00295 }
 All Classes Files Functions Variables Enumerations Enumerator Defines