Scripts:Enhanced rotate demo

From BF2 Technical Information Wiki
Revision as of 23:58, 6 August 2010 by Newacct (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Contents

Enahancements

 July 14, 2005
Enhanced rotate_demo.py 
by: Dave Lawrence  thrash@fragnastika.com
Includes updates by: dackz
Changes
- Fixed apparent issue where FTP credentials require use of '@' (at least in Win)
- Added grossly verbose error logging for troubleshooting FTP problems
- Added cfg option "verbose_log" to enable verbose logging
- Added verbose log file "rotate_demo_log.txt"
  * For console debugging, set verbose_log=0  to log to the console
- Incorporated local file mods by dackz
Usage:
- In Windows it is recommended to use the compiled version of this tool
- In ServerSettings.con you would use something like the following
-		sv.autoDemoHook "adminutils/demo/rotate_demo.exe"
- If you did not receive the exe version of this script, you can compile by:
   * Download ActivePython v2.4		
   * Install ActivePython
   * Download py2exe for Python v2.4!
   * Install py2exe
   * Place the Enhanced rotate_demo.py in AdminUtils\demo
   * From the cmd prompt (with python in your PATH), run:
       python setup.py py2exe
   * py2exe should execute and create a directory: dist
   * AdminUtils\demo\dist contains rotate_demo.exe

Downloads http://activestate.com http://starship.python.net/crew/theller/py2exe

Installation

  1. Browse to adminutils/demo/ in your bf2 server directory
  2. Backup rotate_demo.py. (cp rotate_demo.py rotate_demo.py.bak.)
  3. Download rotate_demo.py or copy the below text into a file manually.
  4. If necessary, download the exe and locate in the same place

Operation

General

By default, a log file called rotate_demo_log.txt will created that logs the actions from the prior execution. When there is an error, you can view each operation that completed prio to the error as well as the eeor itself in this file. In addition, rotate_demo_err.txt still clumsily records the same info it did before.

If you are having problems getting the demo moved the appropriate place, I strongly recommend that you run the script manualy from the command line, and outside of the game. The script takes one parameter which is the filename of the demo file. This filename can be of any file. IF you want to check the rotation features, just make sure the test files end with ".bf2demo" for example

cd /games/bf2
touch test1.bf2demo
python AdminUtils/demo/rotate_demo.py test1.bf2demo

It is *much* easier to debug this way.

Win BF2 and FTP

For some reason I cannot get the rotate_demo.py script to execute properly under a Windows BF2 server using FTP with an FTP username that use a "@". A popular convention on at least cPanel web hosters is to include the server domain name along with the username, separate with "@". For example:

Host: files.myhost.com
User: myhoster@myhost.com
 Pwd: blahblah

With a username as shown above, under Windows, the BF2 server is just not parsing the username correctly and the FTP fails. I have no idea why, although it must have something to do with the BF2 version Python. In any case, if you are using Windows, and you have an FTP username like this, I recommend using the compiled version of this script, rotate_demo.exe. This will work.

Code

Downloadable

These urls are out of date and no longer available The source http://files.fragnastika.net/bf2_rotate_demo/Enhanced/rotate_demo.py

The Win exe version http://files.fragnastika.net/bf2_rotate_demo/Enhanced/rotate_demo.exe

Readable

#! /usr/bin/python
#
# rotate_demo.py: simple file-rotation and index updating script
#
# Requires Python 2.3 or newer.
#
# Theory of operation:
# When automatic demo recording is enabled in the BF2 dedicated server it will
# call a hook program (such as this) when a new demo file is ready for
# publishing. The server will wait for the hook program to complete before
# notifying connected clients of the URL the demo can be downloaded from. It is
# therefore important that all work is done in a blocking manner in this
# program, or clients might try to download demos that aren't in place on the
# web server yet.
#
# Copyright (c)2004 Digital Illusions CE AB
# Author: Andreas Fredriksson

#
# July 14, 2005
# Enhanced rotate_demo.py 
# by: Dave Lawrence  thrash@fragnastika.com
# Includes updates by: dackz
#
# Changes
# - Fixed apparent issue where FTP credentials require use of '@'
# - Added grossly verbose error logging for troubleshooting FTP problems
# - Added cfg option "verbose_log" to enable verbose logging
# - Added verbose log file "rotate_demo_log.txt"
#   * For console debugging, set verbose_log=0  to log to the console
# - Incorporated local file mods by dackz
#
# Usage:
# - In Windows it is recommended to use the compiled version of this tool
# - In ServerSettings.con you would use something like the following
#		sv.autoDemoHook "adminutils/demo/rotate_demo.exe"
# - If you did not receive the exe version of this script, you can compile by:
#		* Download ActivePython v2.41 from http://activestate.com
#		* Install ActivePython
#		* Download py2exe from http://starship.python.net/crew/theller/py2exe  VERSION 2.4!
#		* Install py2exe
# 		* Place the Enhanced rotate_demo.py in AdminUtils\demo
#		* From the cmd prompt (with python in your PATH), run:
#			python setup.py py2exe
#		* py2exe should execute and create a directory: dist
#		* AdminUtils\demo\dist contains rotate_demo.exe
#

import os
import sys
import shutil

# for debugging a hack like this might be useful since stdout and stderr are
# discarded when the script is run
class writer:
	def __init__(self):
		self.stream = open('rotate_demo_log.txt', 'w')
	def write(self, str):
		self.stream.write(str)

# helper function to create directories as needed -- this doesn't care about
# umask or permissions in general so consider this a starting point
def ensure_exists(path):
	try:
		os.stat(path)
	except:
		try:
			os.makedirs(path)
		except:
			pass

# set some sane defaults
options = {
	'use_ftp':'0',
	'ftp_server':'',
	'ftp_target_dir':'',
	'ftp_user':None,
	'ftp_password':None,
	'target_root': 'webroot',
	'file_limit': '10',
	'verbose_log': '1',
}

# parse the config file, if it's there
print "Importing cfg\n"
try:
	config = open('rotate_demo.cfg', 'rt')
	for line_ in config:
		line = line_.strip()
		if len(line) == 0 or line.startswith('#'): continue
		try:
			key, value = line.split('=')
			options[key.strip()] = value.strip()
		except ValueError, ex:
			print ex
except IOError:
	print "I/O Error on cfg read\n"
	pass

if options['verbose_log'] == '1':
	sys.stdout = writer()

# our first argument indicates the demo file which is ready to be moved
path = os.path.normpath(sys.argv[1].replace('"', ''))

# handle local file shuffling (web server on same host as bf2 server, or on network share)
if options['use_ftp'] == '0':
	print "Using local file shuffle\n"
	# this is our target directory (i.e. the download dir)
	target_demo_dir = os.path.join(options['target_root'], 'demos')

	# create the directory structure if it doesn't exist
	ensure_exists(options['target_root'])
	ensure_exists(os.path.join(options['target_root'], 'demos'))

	if os.path.abspath(os.path.dirname(path)) != os.path.abspath(target_demo_dir):
		try:
			# NOTE: this requires atleast Python 2.3
			print "moving '%s' to '%s'" % (path, target_demo_dir)
			shutil.move(path, target_demo_dir)
		except IOError:
			sys.exit(1)

	timestamped = []

	# get a list of .bf2demo files in the target dir (including our own file)
	for pf in filter(lambda x: x.endswith('.bf2demo'), os.listdir(target_demo_dir)):
		try:
			ppath = os.path.join(target_demo_dir, pf)
			os.chmod(ppath, 0644) # make web-readable
			timestamped.append((os.stat(ppath).st_mtime, ppath))
		except IOError:
			pass # don't let I/O errors stop us

	# sort the timestamped file list according to modification time
	# NOTE: this sort is reversed so that older files are at the end of the list
	timestamped.sort(key=lambda f: f[0], reverse=True)

	# delete the oldest files to meet the file limit
	file_limit = int(options['file_limit'])
	for timestamp, deletium in timestamped[file_limit:]:
		try:
			os.remove(deletium)
		except IOError:
			pass # file in use?

	# create the index file
	if 0: # dep: I guess this is superfluous
		idxf = open(os.path.join(options['target_root'], 'index.lst'), 'w')
		for timestamp, keptfile in timestamped[:file_limit]:
			fn = keptfile.split(os.sep)[-1]
			idxf.write('demos/%s\n' % (fn))
		idxf.close()

else: # use ftp
	print "Using FTP\n"
	try:
		import ftplib
		import re

		path.replace('\\\\', '\\')

		path = os.path.normpath(path).replace('\\', '/')

		fn = path
		idx = fn.rfind('/')
		if idx != -1: fn = fn[idx+1:]

		try:
			os.stat(path)
		except:
			# This shouldn't happen normally, only when testing from the cmd line
			print "ERROR- File does not exist: %s\nAborting\n" % (path)
			raise
		
		demof = open(path, 'rb')

		# set up ftp connection
		print "Connecting to:\n\tHost: %s\n\tUser: %s\n\t Pwd: %s\n" % (options['ftp_server'], options['ftp_user'], options['ftp_password'])
		try:
			ftp = ftplib.FTP(options['ftp_server'], options['ftp_user'], options['ftp_password'])
		except:
			print "FTP ERROR: Connect failed!"
			raise
		print "Connected ... \n"

		# change cwd
		print "Changing cwd to %s\n" % (options['ftp_target_dir'])
		try:
			ftp.cwd(options['ftp_target_dir'])
		except:
			print "FTP ERROR: failed to cwd => %s" % (options['ftp_target_dir'])
			raise

		file_limit = int(options['file_limit'])

		print "Retrieving file listing from FTP ...\n"
		try:
			files = ftp.nlst()
		except:
			files = []

		files = filter(lambda x: x.endswith('.bf2demo'), files)
		files.sort()

		for file in files: print "\t" + file

		# store the new file
		print "\nStoring new demo file: %s" % (fn)
		try:
			ftp.storbinary('STOR '+fn, demof)
		except:
			print "FTP ERROR: Upload failed!"
				
		print "\tUpload complete!"
		demof.close()

		# Remove the local file
		print "Removing local demo file %s" % (path)
		try:
			# delete local file
			os.unlink(path)
		except OSError:
			# couldn't unlink local file, what to do?
			print "ERROR- %s Could not be removed!" % (path)
			pass

		# handle remote rotation
		print "\nHandling rotation and removing old FTP demos: file limit = %s" % (file_limit)
		while len(files) >= file_limit:
			# dep: nb: this relies on the data formatting in the bf2demo filenames
			# if you have other
			print '\tdeleting %s' % (files[0])
			try:
				ftp.delete(files[0])
			except:
				print "FTP ERROR: Unable to delete %s" % (files[0])
				pass
			del files[0]

		# bye bye
		ftp.quit()
		print "\nConnection closed"

	except Exception, detail:
		print "\n========================\nROTATE_DEMO ERROR!\n"
		import traceback
		log = open('rotate_demo_err.txt', 'w')
		ex = sys.exc_info()
		traceback.print_exception(ex[0], ex[1], ex[2], 16, log)
		print "%s\n%s\n%s\n%s\n%s" % (ex[0], ex[1], ex[2], 16, log)
		print "========================\n"
		log.write('\n')
		log.close()
		sys.exit(1)
Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox