-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbootstrap.py
181 lines (140 loc) · 5.65 KB
/
bootstrap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# Bootstrapping code.
import sys, os, stackless, gc, logging, traceback, types
dirPath = sys.path[0]
if not len(dirPath):
raise RuntimeError("Expected to find the directory the script was executed in in sys.path[0], but did not.")
# Add the "contrib" directory to the path.
contribDirPath = os.path.join(dirPath, "contrib")
if os.path.exists(contribDirPath) and contribDirPath not in sys.path:
sys.path.append(contribDirPath)
import pysupport
STATE_STARTUP = 0
STATE_RUNNING = 1
STATE_SHUTDOWN = 2
bootstrapState = STATE_STARTUP
def OnClassCreation(class_):
class_.__instances__ = classmethod(pysupport.FindClassInstances)
if not hasattr(class_, "__subclasses__"):
class_.__subclasses__ = classmethod(pysupport.FindClassSubclasses)
class_.__events__ = set()
if bootstrapState != STATE_STARTUP:
print "CREATE", class_
events.ProcessClass(class_)
if bootstrapState != STATE_STARTUP:
events.ClassCreation(class_)
def OnClassUpdate(class_):
if bootstrapState != STATE_STARTUP:
gc.collect()
instances = pysupport.FindInstances(class_)
instanceCount = sum(len(l) for l in instances.itervalues())
print "UPDATE", class_, instanceCount, "instances"
events.ProcessClass(class_)
if bootstrapState != STATE_STARTUP:
events.ClassUpdate(class_)
def OnScriptValidation(scriptFile):
try:
from mudlib import GameCommand
except ImportError:
return
# TODO: Make this more generic.
for k, v in scriptFile.scriptGlobals.iteritems():
if type(v) in (types.ClassType, types.TypeType) and v is not GameCommand:
if issubclass(v, GameCommand) and "Run" in v.__dict__:
raise Exception("Subclasses of GameCommand cannot override Run")
def Run():
global bootstrapState
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s;%(name)s;%(levelname)s;%(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
logging.getLogger().name = "default"
logging.getLogger("namespace").setLevel(logging.INFO)
logging.getLogger("reloader").setLevel(logging.INFO)
stackless.getcurrent().block_trap = True
iniFilename = os.path.join(dirPath, "config.ini")
if not os.path.exists(iniFilename):
print "Please copy 'config.ini.base' to 'config.ini' and modify it appropriately."
sys.exit(0)
# Monkey-patch in the stackless-compatible sockets.
import stacklesssocket
import uthread2
import stacklesslib.main as stacklesslibmain
stacklesssocket._schedule_func = lambda delay=0: stacklesslibmain.sleep(delay)
stacklesssocket._sleep_func = stacklesslibmain.sleep
stacklesssocket.install()
# Install the global event handler.
import __builtin__
from events import EventHandler
__builtin__.events = EventHandler()
# Add the "livecoding" contrib directory to the path.
livecodingDirPath = os.path.join(dirPath, "contrib", "livecoding")
if os.path.exists(livecodingDirPath):
sys.path.append(livecodingDirPath)
# Register the mudlib and game script directories with the livecoding
# module. This will compile and execute them all.
import reloader
#gamePath = os.path.join("games", "room - simple")
gamePath = os.path.join("games", "roguelike")
gameScriptPath = os.path.join(dirPath, gamePath)
mudlibScriptPath = os.path.join(dirPath, "mudlib")
cr = reloader.CodeReloader()
# Register for code reloading updates of managed classes.
# Broadcast an event when we receive an update.
cr.SetClassCreationCallback(OnClassCreation)
cr.SetClassUpdateCallback(OnClassUpdate)
cr.SetValidateScriptCallback(OnScriptValidation)
cr.AddDirectory("mudlib", mudlibScriptPath)
cr.AddDirectory("game", gameScriptPath)
import imp
__builtin__.sorrows = imp.new_module('sorrows')
from mudlib.services import ServiceService
svcSvc = ServiceService()
svcSvc.gameScriptPath = gamePath
svcSvc.gameDataPath = os.path.join(gamePath, "data")
svcSvc.Register()
svcSvc.Start()
del svcSvc
stackless.getcurrent().block_trap = False
bootstrapState = STATE_RUNNING
manualShutdown = False
try:
stacklesslibmain.mainloop.run()
except KeyboardInterrupt:
print
print '** EXITING: Server manually stopping.'
print
if stackless.runcount > 1:
print "Scheduled tasklets:", stackless.runcount
uthread2.PrintTaskletChain(stackless.current)
print
if False:
for entry in stacklesslibmain.event_queue.queue_a:
print "Sleeping tasklets:"
uthread2.PrintTaskletChain(uthread.yieldChannel.queue)
print
for timestamp, channel in uthread.sleepingTasklets:
if channel.queue:
print "Sleep channel (%d) tasklets:" % id(channel)
uthread2.PrintTaskletChain(channel.queue)
print
manualShutdown = True
finally:
cr.EndMonitoring()
bootstrapState = STATE_SHUTDOWN
if manualShutdown:
class HelperClass:
def ShutdownComplete(self):
stacklesslibmain.mainloop.stop()
managerTasklet.kill()
helper = HelperClass()
events.ShutdownComplete.Register(helper.ShutdownComplete)
stackless.tasklet(sorrows.services.Stop)()
# We have most likely killed the stacklesssocket tasklet.
managerTasklet = stacklesssocket.StartManager()
stacklesslibmain.mainloop.run()
logging.info("Shutdown complete")
if __name__ == '__main__':
try:
Run()
finally:
logging.shutdown()