I feel like this must be some kind of scoping issue but after a lot of research I'm still stumped. I'm building a small minecraft server wrapper and it's currently working with the following code (full source on github: Simple Minecraft Server Wrapper - app.py):
mc = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, cwd=results.path)
time.sleep(5)
while run == 1:
print '--- Checking for new versions in ' + str(check_for_new_versions_frequency) + ' seconds.'
time.sleep(check_for_new_versions_frequency)
print '--- Checking for a new version...'
mc.stdin.write('say SMSW - Checking for new version...\n')
mc.stdin.flush()
if up_to_date(current_ver) == False:
mc.stdin.write('say SMSW - New version detected, rebooting for update in 30 seconds...\n')
mc.stdin.flush()
This will start the server and check for new updates at a predetermined interval. This also will message within the game to alert connected players that it is checking for updates and warn them of a reboot if an update is needed. This is working without any issues.
I wanted to clean up the code a bit and move messaging, startup, and shutdown to a separate class called ServerManager. The class works to start the server but messaging does not work. Here's that class:
import time, subprocess
class ServerManager:
def __init__(self, path, server_file, xms=1, xmx=1, gui=False):
self.path = path
self.server_file = server_file
self.online = False
self.xms = xms
self.xmx = xmx
self.gui = gui
def start(self):
global process
command = 'java -jar -Xms' + str(self.xms) + 'G -Xmx' + str(self.xmx) + 'G ' + self.path + self.server_file
if self.gui == False: command += ' nogui'
print command
if self.path !='':self.process = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, cwd=self.path)
if self.path =='':self.process = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE)
print self.server_process
self.online = True
def shutdown(self):
self.message('New version detected, server will be shutting down for maintenance in 1 minute.')
time.sleep(30)
self.message('Shutting down for maintenance in 30 seconds.')
time.sleep(20)
self.message('Shutting down for maintenance in 10 seconds.')
self.message('Have some diamonds for the trouble.')
self.message('give @a minecraft:diamond 5', true)
self.online = False
self.process.terminate()
del process
#Server chat can be passed as ServerManager.message('hello')
def message(self, message, command=False):
print self.server_process
if command == False:
self.process.stdin.write('### SMSW Message: ')
self.process.stdin.flush()
self.process.stdin.write(message)
self.process.stdin.flush()
else:
self.process.stdin.write(message)
self.process.stdin.flush()
The strangest part is when I modify my application to utilize this class, at the points where the server messaging should occur I do not receive any errors. It just doesn't actually do the messaging. I've done a print(process) at the startup and messaging functions at get the same object reference so it seems like it should work. Server shutdown also does not work, I'm guessing it's the same issue as the 'server' object appears to be present but inaccessible for some reason.
Here's the modified main app code that is utilizing the class:
def main():
process_args()
server = ServerManager(results.path, mc_server, 1, 1)
global current_ver
global run
print '*' * 40
print '* Simple Minecraft Server Wrapper'
print '*' * 40
latest_ver = str(get_version())
if current_ver != latest_ver:
download_server(latest_ver)
current_ver = latest_ver
if not server.online:
server.start()
time.sleep(5)
while server.online:
print '--- Checking for new versions in ' + str(check_for_new_versions_frequency) + ' seconds.'
time.sleep(check_for_new_versions_frequency)
print '--- Checking for a new version...'
server.message('Checking for a new version...')
# Checking for new version
if not up_to_date(current_ver):
# new version detected
time.sleep(30)
server.online = False
time.sleep(5)
print '--- Server stopped'
main()
Output from this is:
****************************************
* Simple Minecraft Server Wrapper
****************************************
--- The latest version of Minecraft is 1.8.8
--- Downloading 1.8.8
--- Download complete.
--- Started server with command: java -jar -Xms1G -Xmx1G minecraft_server.jar no
gui
<subprocess.Popen object at 0x029BBDB0>
[10:54:44] [Server thread/INFO]: Starting minecraft server version 1.8.8
[10:54:44] [Server thread/INFO]: Loading properties
[10:54:44] [Server thread/INFO]: Default game type: SURVIVAL
[10:54:44] [Server thread/INFO]: Generating keypair
[10:54:44] [Server thread/INFO]: Starting Minecraft server on *:25565
[10:54:44] [Server thread/INFO]: Using default channel type
[10:54:44] [Server thread/INFO]: Preparing level "world"
[10:54:44] [Server thread/INFO]: Preparing start region for level 0
[10:54:45] [Server thread/INFO]: Done (1.092s)! For help, type "help" or "?"
--- Checking for new versions in 20 seconds.
--- Checking for a new version...
<subprocess.Popen object at 0x029BBDB0>
--- The latest version of Minecraft is 1.8.8
--- Up to date.
--- Checking for new versions in 20 seconds.
--- Checking for a new version...
<subprocess.Popen object at 0x029BBDB0>
The first subprocess object print is from the start function in the class, the second is from the message function. The references match like you would expect but the stdout.write does not work.
Any ideas?