File indexing completed on 2025-01-19 06:55:04
0001 #!/usr/bin/env python 0002 0003 #--------------------------------------------------------------- 0004 # KMuddy scripting support 0005 # 0006 # Run this file directly (as a script from within KMuddy) 0007 # for a basic functionality test 0008 #--------------------------------------------------------------- 0009 0010 import os, sys, socket, select 0011 0012 #--------------------------------------------------------------- 0013 0014 """This module provides full scripting support for KMuddy. 0015 Functions: 0016 0017 initSocket([bufsize]) -- create a new KMuddy connection 0018 closeSocket() -- close the KMuddy connection 0019 getVariable(var) -- get a variable 0020 setVariable(var, value) -- set a variable 0021 unsetVariable(var) -- unset a variable 0022 incVariable(var, [amount]) -- increase var's value 0023 decVariable(var, [amount]) -- decrease var's value 0024 lockVariable(var) -- lock a variable 0025 unlockVariable(var) -- unlock a variable 0026 sendCommand(command) -- send command to MUD 0027 provideResource(resource) -- provide a resource 0028 requestResource(resource) -- request a resource 0029 registerEvent(portno, [func]) -- register an event 0030 unregisterEvent(portno) -- unregister an event 0031 wait4Event() -- wait for an event\n 0032 See method __doc__ properties for details\n""" 0033 0034 evSocks = {} 0035 evPorts = {} 0036 evHandlers = {} 0037 socketName = "" 0038 sock = None 0039 bufferSize = 1024 0040 0041 def initSocket(bufsize = 1024): 0042 global sock, socketName 0043 """initSocket([bufsize])\n 0044 Connect to KMuddy server in order to get/set variables, send commands, etc.\n\n" 0045 bufsize -- length of character buffer (optional, defaults to 32)\n""" 0046 bufferSize = bufsize 0047 socketName = os.environ.get("KMUDDY_SOCKET") 0048 if socketName is None: 0049 raise RuntimeError, "Environment variable KMUDDY_SOCKET is not set.\nDid you activate \"Communicate variables\" in the \"Input/Output\" section of the script properties?" 0050 0051 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 0052 if sock is None: 0053 raise RuntimeError, "Could not create socket" 0054 try: 0055 sock.connect(socketName) 0056 except: 0057 raise RuntimeError, "Could not connect to Kmuddy. Check KMUDDY_SOCKET environment variable." 0058 0059 #--------------------------------------------------------------- 0060 0061 def closeSocket(): 0062 global sock 0063 """closeSocket()\n\nClose connection to KMuddy server. Doesn't hurt to call this at the end of your script.""" 0064 0065 sock.close() 0066 sock = None 0067 0068 #--------------------------------------------------------------- 0069 0070 def getVariable(var): 0071 global sock, bufferSize 0072 """getVariable(var) -> string\n\nReturn value of variable `var'""" 0073 0074 sock.send("get %s\n" % var) 0075 sock.flush() 0076 return sock.recv(bufferSize)[:-2] 0077 0078 #--------------------------------------------------------------- 0079 0080 def setVariable(var, value): 0081 global sock, bufferSize 0082 """setVariable(var, value) -> boolean\n\nSet variable `var' to `value'""" 0083 0084 sock.send("set %s %s\n" % (var, value)) 0085 sock.flush() 0086 return sock.recv(bufferSize)[:-2] == "OK" 0087 0088 #--------------------------------------------------------------- 0089 0090 def unsetVariable(var): 0091 global sock, bufferSize 0092 """unsetVariable(var) -> boolean\n\nRemove variable `var'""" 0093 0094 sock.send("unset %s\n" % var) 0095 sock.flush() 0096 return sock.recv(bufferSize)[:-2] == "OK" 0097 0098 #--------------------------------------------------------------- 0099 0100 def incVariable(var, amount = 1): 0101 global sock, bufferSize 0102 """incVariable(var, [amount]) -> boolean\n\nIncrease variable `var' by `amount' (defaults to 1)""" 0103 0104 sock.send("inc %s %d\n" % (var, amount)) 0105 sock.flush() 0106 return sock.recv(bufferSize)[:-2] == "OK" 0107 0108 #--------------------------------------------------------------- 0109 0110 def decVariable(var, amount = 1): 0111 global sock, bufferSize 0112 """decVariable(var, [amount]) -> boolean\n\nDecrease variable `var' by `amount' (defaults to 1)""" 0113 0114 sock.send("dec %s %d\n" % (var, amount)) 0115 sock.flush() 0116 return sock.recv(bufferSize)[:-2] == "OK" 0117 0118 #--------------------------------------------------------------- 0119 0120 def lockVariable(var): 0121 global sock, bufferSize 0122 """lockVariable(var) -> boolean\n\nLock variable `var'""" 0123 0124 sock.send("lock %s\n" % var) 0125 sock.flush() 0126 return sock.recv(bufferSize)[:-2] == "OK" 0127 0128 #--------------------------------------------------------------- 0129 0130 def unlockVariable(var): 0131 global sock, bufferSize 0132 """unlockVariable(var) -> boolean\n\nUnlock variable `var'""" 0133 0134 sock.send("unlock %s\n" % var) 0135 sock.flush() 0136 return sock.recv(bufferSize)[:-2] == "OK" 0137 0138 #--------------------------------------------------------------- 0139 0140 def sendCommand(command): 0141 global sock, bufferSize 0142 """sendCommand(command) -> boolean\n\nSend a command string to the MUD""" 0143 0144 sock.send("send %s\n" % command) 0145 sock.flush() 0146 return sock.recv(bufferSize)[:-2] == "OK" 0147 0148 #--------------------------------------------------------------- 0149 0150 def provideResource(resource): 0151 global sock, bufferSize 0152 """provideResource(resource) -> boolean\n\nProvide a resource""" 0153 0154 sock.send("provide %s\n" % resource) 0155 sock.flush() 0156 return sock.recv(bufferSize)[:-2] == "OK" 0157 0158 #--------------------------------------------------------------- 0159 0160 def requestResource(resource): 0161 global sock, bufferSize 0162 """requestResource(resource) -> boolean\n\n Request a resource from the MUD""" 0163 0164 sock.send("request %s\n" % resource) 0165 sock.flush() 0166 return sock.recv(bufferSize)[:-2] == "OK" 0167 0168 #--------------------------------------------------------------- 0169 0170 def registerEvent(portno, func = None): 0171 global evSocks, evPorts, evHandlers 0172 """registerEvent(portno, [func]) -> boolean\n 0173 Register/update an event for notification by KMuddy\n 0174 This function binds a TCP socket to the local loopback address on the given port. 0175 The script can then be notified from KMuddy using /notify <portno> <data>. 0176 If the respective port number has been registered before, its handler is updated. 0177 0178 portno -- TCP port number to bind to (1-65535, ports <= 1024 require root privileges) 0179 func -- event handler function (optional) 0180 0181 If func is given, future calls to wait4Event() will transparently call it whenever 0182 the event occurs. 0183 If func is omitted, future calls to wait4Event() will return whenever the event occurs, 0184 yielding a list containing tuples of the form (portno, data_string). 0185 0186 func is a function taking a single string argument containing the text that was 0187 sent to the script. 0188 0189 registerEvent() returns True on success and False in case of an error.""" 0190 0191 if portno in evSocks: 0192 if portno in evHandlers and func is None: 0193 del evHandlers[portno] 0194 return True 0195 return False 0196 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 0197 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 0198 s.setblocking(0) 0199 s.bind(("", portno)) 0200 s.listen(1) 0201 evSocks[portno] = s 0202 evPorts[s] = portno 0203 if func is not None: 0204 evHandlers[portno] = func 0205 return True 0206 0207 #--------------------------------------------------------------- 0208 0209 def unregisterEvent(portno): 0210 global evSocks, evPorts, evHandlers 0211 """unregisterEvent(portno) -> boolean\n 0212 Unregister an event associated to port `portno'\n 0213 Returns False if the event was not registered before, True on success""" 0214 if portno not in evSocks: 0215 return False 0216 del evPorts[evSocks[portno]] 0217 del evSocks[portno] 0218 if portno in evHandlers: 0219 del evHandlers[portno] 0220 return True 0221 0222 #--------------------------------------------------------------- 0223 0224 def wait4Event(timeout = None): 0225 global evSocks, evPorts, evHandlers 0226 """wait4Event([timeout]) -> list of tuples 0227 Wait for an event to occur\n 0228 timeout -- seconds to wait before giving up and returning None (optional), 0229 0 causes immediate return if no data is present.\n 0230 wait4Event() efficiently suspends the script until one or more previously registered 0231 events occur. 0232 For events with an attached event handler the latter is called, getting the received 0233 line passed as the only argument. 0234 If at least one event without an attached event handler occured, a tuple containing the 0235 port number and the received data is added to a list which is returned when all pending 0236 events have been processed. 0237 If all registered events possess an attached event handler, wait4Event() resumes infinitely. 0238 If any event handler returns an actual value (i.e. not None), wait4Event() immediately 0239 returns this value. This should be used for clean script termination. 0240 However, there is no guarantee that all pending events are processed in that case 0241 (although it's highly unlikely that more than one event occurs at a time). 0242 Eventually, if the optional timeout expires, an empty list is returned.""" 0243 0244 while 1: 0245 if evSocks == {}: 0246 return None 0247 retval = [] 0248 handler_retval = None 0249 for s in select.select(evSocks.values(), [], [], timeout)[0]: 0250 port = evPorts[s] 0251 try: 0252 in_s = s.recv(bufferSize) # socket already connected 0253 except socket.error: # new connection 0254 del evSocks[port] 0255 del evPorts[s] 0256 evSocks[port] = s.accept()[0] 0257 evPorts[evSocks[port]] = port 0258 in_s = evSocks[port].recv(bufferSize) 0259 if in_s == "": # conn reset by peer 0260 del evPorts[evSocks[port]] 0261 del evSocks[port] 0262 continue 0263 if port in evHandlers: 0264 for line in in_s[:-1].split("\n"): 0265 handlerRetval = evHandlers[port](line) 0266 if handlerRetval is not None: 0267 return handlerRetval 0268 else: 0269 retval.append((port, in_s)) 0270 if retval != [] or timeout is not None: 0271 return retval 0272 0273 #--------------------------------------------------------------- 0274 0275 def my_func(args): 0276 print "HANDLER CALLED: " + args 0277 return True 0278 0279 #--------------------------------------------------------------- 0280 0281 if __name__ == "__main__": 0282 0283 initSocket() 0284 print "KMUDDY_SOCKET: " + socketName 0285 setVariable("test", "this is some test") 0286 print "Value of variable 'test' has been set" 0287 test = getVariable("test") 0288 print "So, value of test = " + test 0289 unsetVariable("test") 0290 print "The variable test is no longer set" 0291 registerEvent(1234, my_func) 0292 wait4Event() 0293 closeSocket() 0294