![]() |
Beaming Scene Service
2.0
RakNet wrapper for managing data communications between multiple Beaming clients
|
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 }