mirror of
https://github.com/barronwaffles/dwc_network_server_emulator.git
synced 2026-07-08 21:33:52 -05:00
Storage: Super hacky Filter evaulation, needs to be improved later.
This commit is contained in:
parent
cebf17efca
commit
7c522eab2d
60
dwc_network_server_emulator.pyproj
Normal file
60
dwc_network_server_emulator.pyproj
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{1a9e8a26-6cea-4e78-835e-b043356ce360}</ProjectGuid>
|
||||
<ProjectHome>.</ProjectHome>
|
||||
<StartupFile>master_server.py</StartupFile>
|
||||
<SearchPath>
|
||||
</SearchPath>
|
||||
<WorkingDirectory>.</WorkingDirectory>
|
||||
<OutputPath>.</OutputPath>
|
||||
<InterpreterId>00000000-0000-0000-0000-000000000000</InterpreterId>
|
||||
<InterpreterVersion>
|
||||
</InterpreterVersion>
|
||||
<Name>dwc_network_server_emulator</Name>
|
||||
<RootNamespace>dwc_network_server_emulator</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="gamespy_backend_server.py" />
|
||||
<Compile Include="gamespy_gamestats_server.py" />
|
||||
<Compile Include="gamespy_natneg_server.py" />
|
||||
<Compile Include="gamespy_player_search_server.py" />
|
||||
<Compile Include="gamespy_profile_server.py" />
|
||||
<Compile Include="gamespy_qr_server.py" />
|
||||
<Compile Include="gamespy_server_browser_server.py" />
|
||||
<Compile Include="internal_stats_server.py" />
|
||||
<Compile Include="master_server.py" />
|
||||
<Compile Include="nas_server.py" />
|
||||
<Compile Include="storage_server.py" />
|
||||
<Compile Include="gamespy\gs_database.py" />
|
||||
<Compile Include="gamespy\gs_query.py" />
|
||||
<Compile Include="gamespy\gs_utility.py" />
|
||||
<Compile Include="gamespy\__init__.py" />
|
||||
<Compile Include="other\utils.py" />
|
||||
<Compile Include="other\__init__.py" />
|
||||
<Compile Include="tools\import_wiimm_data.py" />
|
||||
<Content Include="www\conntest.nintendowifi.net\public_html\index.html" />
|
||||
<Content Include="www\gamestats.gs.nintendowifi.net\public_html\index.html" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="gamespy" />
|
||||
<Folder Include="other" />
|
||||
<Folder Include="tools" />
|
||||
<Folder Include="www\" />
|
||||
<Folder Include="www\conntest.nintendowifi.net\" />
|
||||
<Folder Include="www\conntest.nintendowifi.net\public_html" />
|
||||
<Folder Include="www\gamestats.gs.nintendowifi.net\" />
|
||||
<Folder Include="www\gamestats.gs.nintendowifi.net\public_html" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" />
|
||||
</Project>
|
||||
20
dwc_network_server_emulator.sln
Normal file
20
dwc_network_server_emulator.sln
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "dwc_network_server_emulator", "dwc_network_server_emulator.pyproj", "{1A9E8A26-6CEA-4E78-835E-B043356CE360}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1A9E8A26-6CEA-4E78-835E-B043356CE360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1A9E8A26-6CEA-4E78-835E-B043356CE360}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A9E8A26-6CEA-4E78-835E-B043356CE360}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1A9E8A26-6CEA-4E78-835E-B043356CE360}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -41,6 +41,7 @@ class StorageHTTPServer(BaseHTTPServer.HTTPServer):
|
|||
|
||||
self.db = sqlite3.connect('storage.db')
|
||||
self.tables = {}
|
||||
self.valid_sql_terms = ['LIKE', '=', 'AND', 'OR']
|
||||
|
||||
logger.log(logging.INFO, "Checking for and creating database tables...")
|
||||
|
||||
|
|
@ -190,6 +191,8 @@ class StorageHTTPServer(BaseHTTPServer.HTTPServer):
|
|||
|
||||
class IllegalColumnAccessException(Exception):
|
||||
pass
|
||||
class FilterSyntaxException(Exception):
|
||||
pass
|
||||
|
||||
class StorageHTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def confirm_columns(self, columndata, table):
|
||||
|
|
@ -204,6 +207,66 @@ class StorageHTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
|
||||
return columns
|
||||
|
||||
def tokenize_filter(self, filter):
|
||||
# TODO: Actual proper tokenization
|
||||
return filter.split()
|
||||
|
||||
def parse_filter(self, table, filter):
|
||||
# I think I need to read up on how to properly parse SQL-like data, but this should do for the stuff I've seen from games so far.
|
||||
out = ''
|
||||
|
||||
if ';' in filter:
|
||||
raise FilterSyntaxException("Semicolon in filter '%s'" & filter)
|
||||
if '\\' in filter:
|
||||
raise FilterSyntaxException("Backslash in filter '%s'" & filter)
|
||||
brace_count = filter.count('(')
|
||||
if brace_count != filter.count(')'):
|
||||
raise FilterSyntaxException("Mismatching brace count in filter '%s'" & filter)
|
||||
|
||||
filter = self.tokenize_filter(filter)
|
||||
|
||||
for f in filter:
|
||||
if f in self.server.tables[table]:
|
||||
# is a table name
|
||||
out += f + ' '
|
||||
elif f.upper() in self.server.valid_sql_terms:
|
||||
# is some SQL term such as LIKE, AND, OR, etc.
|
||||
out += f + ' '
|
||||
elif ( f.startswith("'") and f.endswith("'") ) or ( f.startswith('"') and f.endswith('"') ):
|
||||
# is a string
|
||||
out += f + ' '
|
||||
else:
|
||||
# is nothing valid, abort and return the statement so far
|
||||
out = out.strip()
|
||||
|
||||
# try to make the output still valid by removing trailing connecting tokens
|
||||
last_space = out.rfind(' ')
|
||||
if last_space >= 0:
|
||||
last_token = out[last_space + 1 : ]
|
||||
if last_token in self.server.valid_sql_terms:
|
||||
out = out[ : last_space ]
|
||||
|
||||
return out
|
||||
|
||||
return out
|
||||
|
||||
def append_filter(self, filter, table, statement, where_appended):
|
||||
try:
|
||||
filters = self.parse_filter(table, filter)
|
||||
if filters:
|
||||
if not where_appended:
|
||||
statement += ' WHERE '
|
||||
where_appended = True
|
||||
else:
|
||||
statement += ' AND '
|
||||
statement += ' ( '
|
||||
statement += filters
|
||||
statement += ' ) '
|
||||
except FilterSyntaxException as e:
|
||||
logger.log(logging.WARNING, "FilterSyntaxException: %s by %s", e.message, self.client_address)
|
||||
pass
|
||||
return statement, where_appended
|
||||
|
||||
def do_POST(self):
|
||||
# Alright, in case anyone is wondering: Yes, I am faking a SOAP service
|
||||
# instead of using an actual one. That's because I've tried to do this
|
||||
|
|
@ -249,26 +312,49 @@ class StorageHTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
statement = 'SELECT '
|
||||
statement += ",".join(columns)
|
||||
statement += ' FROM ' + table
|
||||
where_appended = False
|
||||
|
||||
if shortaction == 'SearchForRecords':
|
||||
# this is ugly as hell but SearchForRecords can request specific ownerids like this
|
||||
owneriddata = data.getElementsByTagName('ns1:ownerids')
|
||||
if owneriddata and owneriddata[0] and owneriddata[0].firstChild:
|
||||
oids = owneriddata[0].getElementsByTagName('ns1:int')
|
||||
statement += ' WHERE '
|
||||
if not where_appended:
|
||||
statement += ' WHERE '
|
||||
where_appended = True
|
||||
else:
|
||||
statement += ' AND '
|
||||
statement += ' ( '
|
||||
statement += ' OR '.join('ownerid = '+str(int(oid.firstChild.data)) for oid in oids)
|
||||
statement += ' ) '
|
||||
|
||||
elif shortaction == 'GetMyRecords':
|
||||
profileid = self.server.gamespydb.get_profileid_from_loginticket(loginticket)
|
||||
statement += ' WHERE ownerid = ' + str(profileid)
|
||||
if not where_appended:
|
||||
statement += ' WHERE '
|
||||
where_appended = True
|
||||
else:
|
||||
statement += ' AND '
|
||||
statement += ' ( ownerid = ' + str(profileid) + ' ) '
|
||||
|
||||
elif shortaction == 'GetSpecificRecords':
|
||||
recordids = data.getElementsByTagName('ns1:recordids')[0].getElementsByTagName('ns1:int')
|
||||
|
||||
# limit to requested records
|
||||
statement += ' WHERE '
|
||||
if not where_appended:
|
||||
statement += ' WHERE '
|
||||
where_appended = True
|
||||
else:
|
||||
statement += ' AND '
|
||||
statement += ' ( '
|
||||
statement += ' OR '.join('recordid = '+str(int(r.firstChild.data)) for r in recordids)
|
||||
statement += ' ) '
|
||||
|
||||
# if there's a filter, evaluate it
|
||||
filterdata = data.getElementsByTagName('ns1:filter')
|
||||
if filterdata and filterdata[0] and filterdata[0].firstChild:
|
||||
statement, where_appended = self.append_filter(filterdata[0].firstChild.data, table, statement, where_appended)
|
||||
|
||||
# if only a subset of the data is wanted
|
||||
limit_offset_data = data.getElementsByTagName('ns1:offset')
|
||||
limit_max_data = data.getElementsByTagName('ns1:max')
|
||||
|
|
@ -311,7 +397,13 @@ class StorageHTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
|
||||
elif shortaction == 'GetRecordCount':
|
||||
statement = 'SELECT COUNT(1) FROM ' + table
|
||||
|
||||
filterdata = data.getElementsByTagName('ns1:filter')
|
||||
if filterdata and filterdata[0] and filterdata[0].firstChild:
|
||||
statement, where_appended = self.append_filter(filterdata[0].firstChild.data, table, statement, False)
|
||||
|
||||
logger.log(logging.DEBUG, statement)
|
||||
|
||||
cursor = self.server.db.cursor()
|
||||
cursor.execute(statement)
|
||||
count = cursor.fetchone()[0]
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user