mirror of
https://github.com/polserver/polserver
synced 2026-08-13 08:23:08 -04:00
* Improve webserver performance and add more tests * add more tests and use fmt library * attempt MacOS fix for OpenConnection * add changelog for connection fix
271 lines
7.7 KiB
C++
271 lines
7.7 KiB
C++
use file;
|
|
use uo;
|
|
use os;
|
|
use polsys;
|
|
|
|
const IGNORE_TEST := 255; // only valid for setup or programs
|
|
|
|
// The shard's built-in webserver (pol.cfg: WebServerPort=5006,
|
|
// WebServerPassword=polcore:test; the auth value is base64( "polcore:test" ))
|
|
const WWW_BASE_URL := "http://127.0.0.1:5006";
|
|
const WWW_AUTH_VALUE := "Basic cG9sY29yZTp0ZXN0";
|
|
|
|
// GET (or `method`) a page from the shard's webserver, authenticated unless
|
|
// auth := 0 is passed. Returns the extended response struct.
|
|
function www_get( path, method := "GET", auth := WWW_AUTH_VALUE )
|
|
var options := struct{};
|
|
if ( auth )
|
|
options := struct{ headers := struct{ Authorization := auth } };
|
|
endif
|
|
return HTTPRequest( WWW_BASE_URL + path, method, options, HTTPREQUEST_EXTENDED_RESPONSE );
|
|
endfunction
|
|
|
|
function ret_error( str )
|
|
return error{ errortext := str };
|
|
endfunction
|
|
|
|
function ret_error_not_equal( actual, expected, message )
|
|
if ( actual != expected )
|
|
return ret_error( $"{message}" );
|
|
endif
|
|
|
|
return 1;
|
|
endfunction
|
|
|
|
function createAccountWithChar( accname, psw )
|
|
var a := FindAccount( accname );
|
|
if ( !a )
|
|
a := CreateAccount( accname, psw, 1 );
|
|
if ( !a )
|
|
return ret_error( "Failed to create account" );
|
|
endif
|
|
a.set_uo_expansion( "AOS" );
|
|
a.addcharacter( 0 );
|
|
endif
|
|
var char := a.getcharacter( 1 );
|
|
if ( !char )
|
|
return ret_error( "Could not find char at slot 1" );
|
|
endif
|
|
return char;
|
|
endfunction
|
|
|
|
function dprint( unused what )
|
|
// print( what );
|
|
endfunction
|
|
|
|
class ResourceManager()
|
|
function ResourceManager( this )
|
|
this.resources := array{};
|
|
endfunction
|
|
|
|
function Cleanup( this )
|
|
dprint( $"CLEANUP! {this.resources}" );
|
|
while ( this.resources.size() )
|
|
var resource_entry := this.resources[this.resources.size()];
|
|
var resource := resource_entry[1];
|
|
var cleanup_fn := resource_entry[2];
|
|
|
|
dprint( $"cleanup 0x{resource.serial:x} ({TypeOf( resource )}):" );
|
|
var res := cleanup_fn.call( resource );
|
|
dprint( $" - {res}" );
|
|
this.resources.shrink( this.resources.size() - 1 );
|
|
endwhile
|
|
return 1;
|
|
endfunction
|
|
|
|
function UpdateConfiguration( this, configs, filename := "::config/servspecopt.cfg" )
|
|
var originalConf := ReadFile( filename );
|
|
if ( originalConf == error )
|
|
return ret_error( $"Could not read {filename} file: ${originalConf}" );
|
|
endif
|
|
|
|
var newConf := array;
|
|
foreach line in originalConf
|
|
if ( line.length() > 1 && line[1, 1] != "#" )
|
|
var keyIndex := line.find( "=" );
|
|
if ( keyIndex )
|
|
var key := line[1, keyIndex - 1];
|
|
if ( configs.exists( key ) )
|
|
continue;
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
newConf.append( line );
|
|
endforeach
|
|
|
|
foreach key in configs
|
|
newConf.append( $"{_key_iter}={key}" );
|
|
endforeach
|
|
|
|
var writeResult := WriteFile( filename, newConf );
|
|
if ( writeResult == error )
|
|
return ret_error( $"Could not write ${filename} file: ${writeResult}" );
|
|
endif
|
|
|
|
var res := ReloadConfiguration();
|
|
|
|
// Apend the config before returning error, so we can still restore it.
|
|
this.resources.append( array{ struct{ filename := filename, configuration := originalConf },
|
|
@RestoreConfiguration } );
|
|
if ( !res )
|
|
return res;
|
|
endif
|
|
|
|
return 1;
|
|
endfunction
|
|
|
|
function GrantPrivilege( this, character, privilege )
|
|
var res := uo::GrantPrivilege( character, privilege );
|
|
if ( !res )
|
|
return res;
|
|
endif
|
|
|
|
character.enable( privilege );
|
|
|
|
this.resources.append( array{ { character, privilege }, @RevokePrivilege } );
|
|
|
|
return 1;
|
|
endfunction
|
|
|
|
function RevokePrivilege( privilege_resource )
|
|
var [ character, privilege ] := privilege_resource;
|
|
|
|
return uo::RevokePrivilege( character, privilege );
|
|
endfunction
|
|
|
|
function RestoreConfiguration( configuration_resource )
|
|
var { filename, configuration } := configuration_resource;
|
|
WriteFile( filename, configuration );
|
|
ReloadConfiguration();
|
|
return 1;
|
|
endfunction
|
|
|
|
function CreateMultiAtLocation( this, x, y, z, objtype, flags := 0, realm := _DEFAULT_REALM )
|
|
// Module functions are registered in global scope as well
|
|
var resource :=::CreateMultiAtLocation( x, y, z, objtype, flags, realm );
|
|
if ( !resource )
|
|
return resource;
|
|
endif
|
|
|
|
this.resources.append( array{ resource, @DestroyMultiResource } );
|
|
dprint( $"created resource resource={resource} this.resources={this.resources}" );
|
|
return resource;
|
|
endfunction
|
|
|
|
function DestroyMultiResource( multi )
|
|
dprint( $"cleanup multi 0x{multi.serial:x}" );
|
|
return DestroyMulti( multi );
|
|
endfunction
|
|
|
|
function CreateItemAtLocation( this, x, y, z, objtype, amount := 1, realm := _DEFAULT_REALM )
|
|
var resource := uo::CreateItemAtLocation( x, y, z, objtype, amount, realm );
|
|
if ( !resource )
|
|
return resource;
|
|
endif
|
|
this.resources.append( array{ resource, @DestroyItemResource } );
|
|
return resource;
|
|
endfunction
|
|
|
|
function CreateItemInContainer( this, container, objtype, amount := 1, x := -1, y := -1 )
|
|
var resource := uo::CreateItemInContainer( container, objtype, amount, x, y );
|
|
if ( !resource )
|
|
return resource;
|
|
endif
|
|
this.resources.append( array{ resource, @DestroyItemResource } );
|
|
return resource;
|
|
endfunction
|
|
|
|
function Start_Script( this, script_name, byref param := 0 )
|
|
var resource := os::Start_Script( script_name, param );
|
|
if ( !resource )
|
|
return resource;
|
|
endif
|
|
this.resources.append( array{ resource, @DestroyScriptResource } );
|
|
return resource;
|
|
endfunction
|
|
|
|
function DestroyScriptResource( script )
|
|
dprint( $"cleanup script {script} {script.state} {script.pid}" );
|
|
// Swallow the "Script has been destroyed" error
|
|
return script.kill() ?: 1;
|
|
endfunction
|
|
|
|
function DestroyItemResource( item )
|
|
dprint( $"cleanup item 0x{item.serial:x}" );
|
|
return DestroyItem( item );
|
|
endfunction
|
|
|
|
function CreateNPCFromTemplate( this, template, x, y, z, override_properties := 0,
|
|
realm := _DEFAULT_REALM, forcelocation := 0 )
|
|
|
|
var resource := uo::CreateNPCFromTemplate( template, x, y, z, override_properties, realm,
|
|
forcelocation );
|
|
if ( !resource )
|
|
return resource;
|
|
endif
|
|
this.resources.append( array{ resource, @DestroyNpcResource } );
|
|
return resource;
|
|
endfunction
|
|
|
|
function DestroyNpcResource( npc )
|
|
dprint( $"cleanup npc {npc.name} 0x{npc.serial:x}" );
|
|
var x := npc.x, y := npc.y, z := npc.z, serial := npc.serial;
|
|
var res := npc.kill();
|
|
if ( !res )
|
|
return res;
|
|
endif
|
|
|
|
var corpses := ListItemsNearLocationOfType( x, y, z, 0, 0x2006 );
|
|
foreach corpse in corpses
|
|
if ( serial == corpse.ownerserial )
|
|
return DestroyItem( corpse );
|
|
endif
|
|
endforeach
|
|
|
|
return ret_error( $"Could not find corpse for NPC 0x{serial:x} at ({x}, {y}, {z}) (corpses: {corpses.size()})" );
|
|
endfunction
|
|
|
|
function AddRealm( this, realm_name, base_realm )
|
|
var res := polsys::AddRealm( realm_name, base_realm );
|
|
if ( !res )
|
|
return res;
|
|
endif
|
|
|
|
this.resources.append( array{ realm_name, @DestroyRealmResource } );
|
|
|
|
return res;
|
|
endfunction
|
|
|
|
function DestroyRealmResource( realm_name )
|
|
return DeleteRealm( realm_name );
|
|
endfunction
|
|
endclass
|
|
|
|
function copy_file( source, destination )
|
|
var file_in := OpenBinaryFile( source, OPENMODE_IN );
|
|
if ( !file_in )
|
|
return file_in;
|
|
endif
|
|
|
|
var file_out := OpenBinaryFile( destination, OPENMODE_OUT | OPENMODE_TRUNC );
|
|
if ( !file_out )
|
|
return file_out;
|
|
endif
|
|
|
|
var byte, i := 0;
|
|
|
|
do
|
|
byte := file_in.getInt8();
|
|
if ( byte == error )
|
|
break;
|
|
endif
|
|
file_out.setInt8( byte );
|
|
dowhile ( 1 );
|
|
|
|
file_in.close();
|
|
file_out.close();
|
|
|
|
return 1;
|
|
endfunction
|
|
|