Mercurial > traipse_dev
diff orpg/networking/mplay_server_gui.py @ 0:4385a7d0efd1 grumpy-goblin
Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author | sirebral |
---|---|
date | Tue, 14 Jul 2009 16:41:58 -0500 |
parents | |
children | c97c641a76fd |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/orpg/networking/mplay_server_gui.py Tue Jul 14 16:41:58 2009 -0500 @@ -0,0 +1,602 @@ +#!/usr/bin/env python +# +# OpenRPG Server Graphical Interface +# GNU General Public License +# + +__appname__=' OpenRPG GUI Server v0.7 ' +__version__='$Revision: 1.26 $'[11:-2] +__cvsinfo__='$Id: mplay_server_gui.py,v 1.26 2007/11/06 00:32:39 digitalxero Exp $'[5:-2] +__doc__=""" +OpenRPG Server Graphical Interface +""" + +import os +import sys +import time +import types +import orpg.dirpath +import orpg.systempath +from orpg.orpg_wx import * +import webbrowser +from threading import Thread +from meta_server_lib import post_server_data, remove_server +from mplay_server import mplay_server + +# Constants ###################################### +SERVER_RUNNING = 1 +SERVER_STOPPED = 0 +MENU_START_SERVER = wx.NewId() +MENU_STOP_SERVER = wx.NewId() +MENU_EXIT = wx.NewId() +MENU_REGISTER_SERVER = wx.NewId() +MENU_UNREGISTER_SERVER = wx.NewId() +MENU_START_PING_PLAYERS = wx.NewId() +MENU_STOP_PING_PLAYERS = wx.NewId() +MENU_PING_INTERVAL = wx.NewId() + +# Add our menu id's for our right click popup +MENU_PLAYER_BOOT = wx.NewId() +MENU_PLAYER_CREATE_ROOM = wx.NewId() +MENU_PLAYER_SEND_MESSAGE = wx.NewId() +MENU_PLAYER_SEND_ROOM_MESSAGE = wx.NewId() +MENU_PLAYER_SEND_SERVER_MESSAGE = wx.NewId() + +# Our new event type that gets posted from one +# thread to another +wxEVT_LOG_MESSAGE = wx.NewEventType() +wxEVT_FUNCTION_MESSAGE = wx.NewEventType() + +# Our event connector -- wxEVT_LOG_MESSAGE +EVT_LOG_MESSAGE = wx.PyEventBinder(wxEVT_LOG_MESSAGE, 1) + +# Our event connector -- wxEVT_FUNCTION_MESSAGE +EVT_FUNCTION_MESSAGE = wx.PyEventBinder(wxEVT_FUNCTION_MESSAGE, 1) + +# Utils ########################################## +def format_bytes(b): + f = ['b', 'Kb', 'Mb', 'Gb'] + i = 0 + while i < 3: + if b < 1024: + return str(b) + f[i] + else: + b = b/1024 + i += 1 + return str(b) + f[3] + +# wxEVT_LOG_MESSAGE +# MessageLogEvent ############################### +class MessageLogEvent(wx.PyEvent): + def __init__( self, message ): + wx.PyEvent.__init__( self ) + self.SetEventType(wxEVT_LOG_MESSAGE) + self.message = message + +# wxEVT_TUPLE_MESSAGE +# MessageLogEvent ############################### +class MessageFunctionEvent(wx.PyEvent): + def __init__( self, func, message ): + wx.PyEvent.__init__( self ) + self.SetEventType(wxEVT_FUNCTION_MESSAGE) + self.func = func + self.message = message + +# ServerConfig Object ############################ +class ServerConfig: + """ This class contains configuration + setting used to control the server. + """ + + def __init__(self, owner ): + """ Loads default configuration settings. + """ + OPENRPG_PORT = 9775 + self.owner = owner + + def load_xml(self, xml): + """ Load configuration from XML data. + xml (xml) -- xml string to parse + """ + pass + + def save_xml(self): + """ Returns XML file representing + the active configuration. + """ + pass + +# Server Monitor ################################# + +class ServerMonitor(Thread): + """ Monitor thread for GameServer. """ + def __init__(self, cb, conf, name, pwd): + """ Setup the server. """ + Thread.__init__(self) + self.cb = cb + self.conf = conf + self.serverName = name + self.bootPwd = pwd + + def log(self, mesg): + if type(mesg) == types.TupleType: + func, msg = mesg + event = MessageFunctionEvent( func, msg ) + else: + event = MessageLogEvent( mesg ) + wx.PostEvent( self.conf.owner, event ) + del event + + def run(self): + """ Start the server. """ + self.server = mplay_server(self.log, self.serverName ) + self.server.initServer(bootPassword=self.bootPwd, reg="No") + self.alive = 1 + while self.alive: + time.sleep(3) + + def stop(self): + """ Stop the server. """ + self.server.kill_server() + self.alive = 0 + +# GUI Server ##################################### +# Parent = notebook +# Main = GUI +class Connections(wx.ListCtrl): + def __init__( self, parent, main ): + wx.ListCtrl.__init__( self, parent, -1, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT|wx.SUNKEN_BORDER|wx.EXPAND|wx.LC_HRULES ) + self.main = main + self.roomList = { "0" : "Lobby" } + self._imageList = wx.ImageList( 16, 16, False ) + img = wx.Image(orpg.dirpath.dir_struct["icon"]+"player.gif", wx.BITMAP_TYPE_GIF).ConvertToBitmap() + self._imageList.Add( img ) + img = wx.Image(orpg.dirpath.dir_struct["icon"]+"player-whisper.gif", wx.BITMAP_TYPE_GIF).ConvertToBitmap() + self._imageList.Add( img ) + self.SetImageList( self._imageList, wx.IMAGE_LIST_SMALL ) + + # Set The columns + self.InsertColumn(0, "ID") + self.InsertColumn(1, "Player") + self.InsertColumn(2, "Status") + self.InsertColumn(3, "Room") + self.InsertColumn(4, "Version") + self.InsertColumn(5, "Role") + self.InsertColumn(6, "IP") + self.InsertColumn(7, "Ping") + + # Set the column widths + self.AutoAjust() + + # Build our pop up menu to do cool things with the players in the list + self.menu = wx.Menu() + self.menu.SetTitle( "Player Menu" ) + self.menu.Append( MENU_PLAYER_BOOT, "Boot Player" ) + self.menu.AppendSeparator() + self.menu.Append( MENU_PLAYER_SEND_MESSAGE, "Send Message" ) + self.menu.Append( MENU_PLAYER_SEND_SERVER_MESSAGE, "Broadcast Server Message" ) + + # Associate our events + self.Bind(wx.EVT_RIGHT_DOWN, self.OnPopupMenu) + self.Bind(wx.EVT_MENU, self.OnPopupMenuItem, id=MENU_PLAYER_BOOT) + self.Bind(wx.EVT_MENU, self.OnPopupMenuItem, id=MENU_PLAYER_SEND_MESSAGE) + self.Bind(wx.EVT_MENU, self.OnPopupMenuItem, id=MENU_PLAYER_SEND_ROOM_MESSAGE) + self.Bind(wx.EVT_MENU, self.OnPopupMenuItem, id=MENU_PLAYER_SEND_SERVER_MESSAGE) + + def add(self, player): + i = self.InsertImageStringItem( 0, player["id"], 0 ) + self.SetStringItem( i, 1, self.stripHtml( player["name"] ) ) + self.SetStringItem( i, 2, self.stripHtml( player["status"] ) ) + self.SetStringItem( i, 3, "ROOM" ) + self.SetStringItem( i, 4, self.stripHtml( player["version"] ) ) + self.SetStringItem( i, 5, self.stripHtml( player["role"] ) ) + self.SetStringItem( i, 6, self.stripHtml( player["ip"] ) ) + self.SetStringItem (i, 7, "PING" ) + self.SetItemData( i, int(player["id"]) ) + self.AutoAjust() + + def remove(self, id): + i = self.FindItemData( -1, int(id) ) + self.DeleteItem( i ) + self.AutoAjust() + + def AutoAjust(self): + self.SetColumnWidth(0, -1) + self.SetColumnWidth(1, -1) + self.SetColumnWidth(2, -1) + self.SetColumnWidth(3, -1) + self.SetColumnWidth(4, -1) + self.SetColumnWidth(5, -1) + self.SetColumnWidth(6, -1) + self.SetColumnWidth(7, -1) + self.Refresh() + + def update(self, player): + i = self.FindItemData( -1, int(player["id"]) ) + if i > -1: + self.SetStringItem(i, 1, player["name"]) + self.SetStringItem(i, 2, self.stripHtml( player["status"] ) ) + self.AutoAjust() + else: + self.add(player) + + def updateRoom( self, data ): + (from_id, id) = data + i = self.FindItemData( -1, int(from_id) ) + self.SetStringItem( i, 3, self.roomList[id] ) + self.SetStringItem( i, 5, "Lurker") + self.Refresh() + + def setPlayerRole( self, id, role ): + i = self.FindItemData( -1, int(id) ) + self.SetStringItem( i, 5, role ) + + def stripHtml( self, name ): + ret_string = "" + x = 0 + in_tag = 0 + for x in range( len(name) ): + if name[x] == "<" or name[x] == ">" or in_tag == 1 : + if name[x] == "<" : + in_tag = 1 + elif name[x] == ">" : + in_tag = 0 + else : + pass + else : + ret_string = ret_string + name[x] + return ret_string + + # When we right click, cause our popup menu to appear + def OnPopupMenu( self, event ): + pos = wx.Point( event.GetX(), event.GetY() ) + (item, flag) = self.HitTest( pos ) + if item > -1: + self.selectedItem = item + self.PopupMenu( self.menu, pos ) + + # Process the events associated with our popup menu + def OnPopupMenuItem( self, event ): + # if we are not running, the player list is empty anyways + if self.main.STATUS == SERVER_RUNNING: + menuItem = event.GetId() + playerID = str( self.GetItemData( self.selectedItem ) ) + idList = self.main.server.server.groups + groupID = 0 + if menuItem == MENU_PLAYER_BOOT: + print "booting player: ", playerID + self.main.server.server.del_player( playerID, groupID ) + self.main.server.server.check_group( playerID, groupID ) + self.remove( playerID ) + elif menuItem == MENU_PLAYER_SEND_MESSAGE: + print "send a message..." + msg = self.GetMessageInput( "Send a message to player" ) + if len(msg): + self.main.server.server.send( msg, playerID, str(groupID) ) +# Leave this in for now. +# elif menuItem == MENU_PLAYER_SEND_TO_ROOM: +# print "Send message to room..." +# msg = self.GetMessageInput( "Send message to room of this player") +# if len(msg): +# self.main.server.server.send_to_group( 0, GroupID, msg ) + + elif menuItem == MENU_PLAYER_SEND_SERVER_MESSAGE: + print "broadcast a message..." + msg = self.GetMessageInput( "Broadcast Server Message" ) + # If we got a message back, send it + if len(msg): + self.main.server.server.broadcast( msg ) + + def GetMessageInput( self, title ): + prompt = "Please enter the message you wish to send:" + msg = wx.TextEntryDialog(self, prompt, title) + msg.ShowModal() + msg.Destroy() + return msg.GetValue() + +class ServerGUI(wx.Frame): + STATUS = SERVER_STOPPED + + def __init__(self, parent, id, title): + wx.Frame.__init__(self, parent, id, title, size = (760, 560) ) + if wx.Platform == '__WXMSW__': + icon = wx.Icon( orpg.dirpath.dir_struct["icon"]+'WAmisc9.ico', wx.BITMAP_TYPE_ICO ) + else: + icon = wx.Icon( orpg.dirpath.dir_struct["icon"]+'connect.gif', wx.BITMAP_TYPE_GIF ) + self.SetIcon(icon) + self.serverName = "Server Name" + self.bootPwd = "" + + # Register our events to process -- notice the custom event handler + self.Bind(wx.EVT_CLOSE, self.OnExit) + self.Bind(EVT_LOG_MESSAGE, self.OnLogMessage) + self.Bind(EVT_FUNCTION_MESSAGE, self.OnFunctionMessage) + + # Creat GUI + self.build_menu() + self.build_body() + self.build_status() + + # Server Callbacks + cb = {} + cb["log"] = self.Log + cb["connect"] = self.OnConnect + cb["disconnect"] = self.OnDisconnect + cb["update"] = self.OnUpdatePlayer + cb["data_recv"] = self.OnDataRecv + cb["data_sent"] = self.OnDataSent + cb["create_group"] = self.OnCreateGroup + cb["delete_group"] = self.OnDeleteGroup + cb["join_group"] = self.OnJoinGroup + cb["role"] = self.OnSetRole + self.callbacks = cb + + # Misc. + self.conf = ServerConfig(self) + self.total_messages_received = 0 + self.total_data_received = 0 + self.total_messages_sent = 0 + self.total_data_sent = 0 + + ### Build GUI ############################################ + + def build_menu(self): + """ Build the GUI menu. """ + self.mainMenu = wx.MenuBar() + # File Menu + menu = wx.Menu() + # Start + menu.Append( MENU_START_SERVER, 'Start', 'Start server.') + self.Bind(wx.EVT_MENU, self.OnStart, id=MENU_START_SERVER) + # Stop + menu.Append( MENU_STOP_SERVER, 'Stop', 'Shutdown server.') + self.Bind(wx.EVT_MENU, self.OnStop, id=MENU_STOP_SERVER) + # Exit + menu.AppendSeparator() + menu.Append( MENU_EXIT, 'E&xit', 'Exit application.') + self.Bind(wx.EVT_MENU, self.OnExit, id=MENU_EXIT) + self.mainMenu.Append(menu, '&Server') + # Registration Menu + menu = wx.Menu() + # Register + menu.Append( MENU_REGISTER_SERVER, 'Register', 'Register with OpenRPG server directory.') + self.Bind(wx.EVT_MENU, self.OnRegister, id=MENU_REGISTER_SERVER) + # Unregister + menu.Append( MENU_UNREGISTER_SERVER, 'Unregister', 'Unregister from OpenRPG server directory.') + self.Bind(wx.EVT_MENU, self.OnUnregister, id=MENU_UNREGISTER_SERVER) + # Add the registration menu + self.mainMenu.Append( menu, '&Registration' ) + # Server Configuration Menu + menu = wx.Menu() + # Ping Connected Players + menu.Append( MENU_START_PING_PLAYERS, 'Start Ping', 'Ping players to validate remote connection.' ) + self.Bind(wx.EVT_MENU, self.PingPlayers, id=MENU_START_PING_PLAYERS) + # Stop Pinging Connected Players + menu.Append( MENU_STOP_PING_PLAYERS, 'Stop Ping', 'Stop validating player connections.' ) + self.Bind(wx.EVT_MENU, self.StopPingPlayers, id=MENU_STOP_PING_PLAYERS) + # Set Ping Interval + menu.Append( MENU_PING_INTERVAL, 'Ping Interval', 'Change the ping interval.' ) + self.Bind(wx.EVT_MENU, self.ConfigPingInterval, id=MENU_PING_INTERVAL) + self.mainMenu.Append( menu, '&Configuration' ) + # Add the menus to the main menu bar + self.SetMenuBar( self.mainMenu ) + # Disable register, unregister & stop server by default + self.mainMenu.Enable( MENU_STOP_SERVER, False ) + self.mainMenu.Enable( MENU_REGISTER_SERVER, False ) + self.mainMenu.Enable( MENU_UNREGISTER_SERVER, False ) + # Disable the ping menu items + self.mainMenu.Enable( MENU_START_PING_PLAYERS, False ) + self.mainMenu.Enable( MENU_STOP_PING_PLAYERS, False ) + self.mainMenu.Enable( MENU_PING_INTERVAL, False ) + + def build_body(self): + """ Create the ViewNotebook and logger. """ + splitter = wx.SplitterWindow(self, -1, style=wx.NO_3D | wx.SP_3D) + nb = wx.Notebook( splitter, -1 ) + self.conns = Connections( nb, self ) + nb.AddPage( self.conns, "Players" ) +#Not sure why this is Remarked TaS - Sirebral + #nb.AddPage( self.conns, "Rooms" ) + #self.msgWindow = HTMLMessageWindow( nb ) + #nb.AddPage( self.msgWindow, "Messages" ) + + log = wx.TextCtrl(splitter, -1, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL) + wx.Log.SetActiveTarget( wx.LogTextCtrl(log) ) + splitter.SplitHorizontally(nb, log, 400) + splitter.SetMinimumPaneSize(40) + self.nb = nb + self.log = log + + def build_status(self): + """ Create status bar and set defaults. """ + sb = wx.StatusBar(self, -1) + sb.SetFieldsCount(5) + sb.SetStatusWidths([-1, 115, 115, 65, 200]) + sb.SetStatusText("Sent: 0", 1) + sb.SetStatusText("Recv: 0", 2) + sb.SetStatusText("Stopped", 3) + sb.SetStatusText("Unregistered", 4) + self.SetStatusBar(sb) + self.sb = sb + + def show_error(self, mesg, title = "Error"): + """ Display an error. + mesg (str) -- error message to display + title (str) -- title of window + """ + dlg = wx.MessageDialog(self, mesg, title, wx.OK | wx.ICON_EXCLAMATION) + dlg.ShowModal() + dlg.Destroy() + + + # Event handler for out logging event + def OnLogMessage( self, event ): + self.Log( event.message ) + + # Event handler for out logging event + def OnFunctionMessage( self, event ): + self.callbacks[event.func]( event.message ) + + ### Server Callbacks ##################################### + def Log(self, log): + wx.LogMessage(str(log)) + + def OnConnect(player, self, data): + self.conns.add(player) + + def OnDisconnect(self, id): + self.conns.remove(id) + + def OnUpdatePlayer(self, data): + self.conns.update(data) + + def OnDataSent(self, bytes): + self.total_messages_sent += 1 + self.total_data_sent += bytes + self.sb.SetStatusText("Sent: %s (%d)" % (format_bytes(self.total_data_sent), self.total_messages_sent), 1) + + def OnDataRecv(self, bytes): + self.total_messages_received += 1 + self.total_data_received += bytes + self.sb.SetStatusText("Recv: %s (%d)" % (format_bytes(self.total_data_received), self.total_messages_received), 2) + + def OnCreateGroup( self, data ): + print "room list: ", self.conns.roomList + self.conns.roomList[id] = name + (id, name) = data + print "room list: ", self.conns.roomList + + def OnDeleteGroup( self, data ): + (from_id, id) = data +# del self.conns.roomList[id] + print "OnDeleteGroup room list: ", self.conns.roomList, id + + def OnJoinGroup( self, data ): + self.conns.updateRoom( data ) + + def OnSetRole( self, data ): + (id, role) = data + self.conns.setPlayerRole( id, role ) + + ### Misc. ################################################ + def OnStart(self, event = None): + """ Start server. """ + if self.STATUS == SERVER_STOPPED: + serverNameEntry = wx.TextEntryDialog( self, "Please Enter The Server Name You Wish To Use:", + "Server's Name", self.serverName, wx.OK|wx.CANCEL|wx.CENTRE ) + if serverNameEntry.ShowModal() == wx.ID_OK: + self.serverName = serverNameEntry.GetValue() + serverPasswordEntry = wx.TextEntryDialog(self, "Please Enter The Server Admin Password:", + "Server's Password", self.bootPwd, wx.OK|wx.CANCEL|wx.CENTRE) + if serverPasswordEntry.ShowModal() == wx.ID_OK: + self.bootPwd = serverPasswordEntry.GetValue() + if len(self.serverName): + wx.BeginBusyCursor() + self.server = ServerMonitor(self.callbacks, self.conf, self.serverName, self.bootPwd) + self.server.start() + self.STATUS = SERVER_RUNNING + self.sb.SetStatusText("Running", 3) + self.SetTitle(__appname__ + "- (running) - (unregistered)") + self.mainMenu.Enable( MENU_START_SERVER, False ) + self.mainMenu.Enable( MENU_STOP_SERVER, True ) + self.mainMenu.Enable( MENU_REGISTER_SERVER, True ) + wx.EndBusyCursor() + else: + self.show_error("Server is already running.", "Error Starting Server") + + def OnStop(self, event = None): + """ Stop server. """ + if self.STATUS == SERVER_RUNNING: + self.OnUnregister() + self.server.stop() + self.STATUS = SERVER_STOPPED + self.sb.SetStatusText("Stopped", 3) + self.SetTitle(__appname__ + "- (stopped) - (unregistered)") + self.mainMenu.Enable( MENU_STOP_SERVER, False ) + self.mainMenu.Enable( MENU_START_SERVER, True ) + self.mainMenu.Enable( MENU_REGISTER_SERVER, False ) + self.mainMenu.Enable( MENU_UNREGISTER_SERVER, False ) + # Delete any items that are still in the player list + self.conns.DeleteAllItems() + + def OnRegister(self, event = None): + """ Call into mplay_server's register() function. + This will begin registerThread(s) to keep server + registered with configured metas + """ + if len( self.serverName ): + wx.BeginBusyCursor() + self.server.server.register(self.serverName) + self.sb.SetStatusText( ("%s" % (self.serverName)), 4 ) + self.mainMenu.Enable( MENU_REGISTER_SERVER, False ) + self.mainMenu.Enable( MENU_UNREGISTER_SERVER, True ) + self.mainMenu.Enable( MENU_STOP_SERVER, False ) + self.SetTitle(__appname__ + "- (running) - (registered)") + wx.EndBusyCursor() + + def OnUnregister(self, event = None): + """ Call into mplay_server's unregister() function. + This will kill any registerThreads currently running + and result in the server being de-listed + from all metas + """ + wx.BeginBusyCursor() + self.server.server.unregister() + self.sb.SetStatusText( "Unregistered", 4 ) + self.mainMenu.Enable( MENU_UNREGISTER_SERVER, False ) + self.mainMenu.Enable( MENU_REGISTER_SERVER, True ) + self.mainMenu.Enable( MENU_STOP_SERVER, True ) + self.SetTitle(__appname__ + "- (running) - (unregistered)") + wx.EndBusyCursor() + + def PingPlayers( self, event = None ): + "Ping all players that are connected at a periodic interval, detecting dropped connections." + wx.BeginBusyCursor() + wx.Yield() + wx.EndBusyCursor() + + def StopPingPlayers( self, event = None ): + "Stop pinging connected players." + + def ConfigPingInterval( self, event = None ): + "Configure the player ping interval. Note that all players are pinged on a single timer." + + def OnExit(self, event = None): + """ Quit the program. """ + self.OnStop() + wx.CallAfter(self.Destroy) + +class ServerGUIApp(wx.App): + def OnInit(self): + # Make sure our image handlers are loaded before we try to display anything + wx.InitAllImageHandlers() + self.splash = wx.SplashScreen(wx.Bitmap(orpg.dirpath.dir_struct["icon"]+'splash.gif'), + wx.SPLASH_CENTRE_ON_SCREEN|wx.SPLASH_TIMEOUT, + 2000, + None) + self.splash.Show(True) + wx.Yield() + wx.CallAfter(self.AfterSplash) + return True + + def AfterSplash(self): + self.splash.Close(True) + frame = ServerGUI(None, -1, __appname__ + "- (stopped) - (unregistered)") + frame.Show(True) + frame.Raise() + self.SetTopWindow(frame) + +class HTMLMessageWindow(wx.html.HtmlWindow): + "Widget used to present user to admin messages, in HTML format, to the server administrator" + + # Init using the derived from class + def __init__( self, parent ): + wx.html.HtmlWindow.__init__( self, parent ) + def OnLinkClicked( self, ref ): + "Open an external browser to resolve our About box links!!!" + href = ref.GetHref() + webbrowser.open( href ) + +if __name__ == '__main__': + app = ServerGUIApp(0) + app.MainLoop()