python 3 conversion
included missing language_tools file fixed hgignore added documentation txt files --HG-- branch : mung
This commit is contained in:
parent
a70737f90f
commit
0b3c747e93
14 changed files with 139 additions and 31 deletions
|
@ -1,4 +1,7 @@
|
||||||
from builtins_code import bi
|
from builtins_code import bi
|
||||||
|
|
||||||
|
__all__ = ['builtin_map']
|
||||||
|
|
||||||
builtin_map = {}
|
builtin_map = {}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ class builtin_functions(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def serverlog(vm, args):
|
def serverlog(vm, args):
|
||||||
print "server_log: %s" % (args,)
|
print("server_log: %s" % (args,))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(vm, args):
|
def create(vm, args):
|
||||||
|
|
|
@ -6,7 +6,7 @@ import optimizer
|
||||||
|
|
||||||
|
|
||||||
def coerce(value):
|
def coerce(value):
|
||||||
from language_types import *
|
from language_types import VMInteger, VMList, VMString, VMTable, VMObjRef, VMFloat, VMType
|
||||||
if isinstance(value, int):
|
if isinstance(value, int):
|
||||||
return VMInteger(value)
|
return VMInteger(value)
|
||||||
elif isinstance(value, (tuple, list)):
|
elif isinstance(value, (tuple, list)):
|
||||||
|
@ -165,7 +165,7 @@ class CallBuiltin(CodeOp):
|
||||||
@tokenparser
|
@tokenparser
|
||||||
def parse(tokens):
|
def parse(tokens):
|
||||||
#if not tokens[0] in builtin_map:
|
#if not tokens[0] in builtin_map:
|
||||||
# raise ParseException, 'Attempt to call undefined builtin function: "%s"' % (tokens[0],)
|
# raise ParseException('Attempt to call undefined builtin function: "%s"' % (tokens[0],))
|
||||||
return codejoin(tokens[0], tokens[1], CallBuiltin())
|
return codejoin(tokens[0], tokens[1], CallBuiltin())
|
||||||
|
|
||||||
class CallFunction(CodeOp):
|
class CallFunction(CodeOp):
|
||||||
|
@ -319,7 +319,7 @@ class Assignment(CodeOp):
|
||||||
elif isinstance(var, VMFileRef):
|
elif isinstance(var, VMFileRef):
|
||||||
var = var.ref() + [SetFile()]
|
var = var.ref() + [SetFile()]
|
||||||
else:
|
else:
|
||||||
raise ValueError, "Assignment to unknown type: %s" % (var,)
|
raise ValueError("Assignment to unknown type: %s" % (var,))
|
||||||
|
|
||||||
return codejoin(tokens[2:], var)
|
return codejoin(tokens[2:], var)
|
||||||
return tokens
|
return tokens
|
||||||
|
|
3
dbdoc.txt
Normal file
3
dbdoc.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
DATABASE FORMAT SPECIFICATION
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -24,7 +24,7 @@ def tokenparser(func):
|
||||||
for x in gd:
|
for x in gd:
|
||||||
if hasattr(gd[x], "parse") and gd[x].parse == newfunc:
|
if hasattr(gd[x], "parse") and gd[x].parse == newfunc:
|
||||||
funcobj = x
|
funcobj = x
|
||||||
print "Error with %s.parse tokens: %s" % (funcobj, tokens)
|
print("Error with %s.parse tokens: %s" % (funcobj, tokens))
|
||||||
traceback.print_exc(e)
|
traceback.print_exc(e)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,14 @@ def disallow_keywords(tokens,keywords=None):
|
||||||
for t in tokens:
|
for t in tokens:
|
||||||
if isinstance(t, VMIdent):
|
if isinstance(t, VMIdent):
|
||||||
if t.name in keywords:
|
if t.name in keywords:
|
||||||
raise ParseException, "Restricted keyword: %s" % (t.name,)
|
raise ParseException("Restricted keyword: %s" % (t.name,))
|
||||||
elif isinstance(t, unicode):
|
elif isinstance(t, unicode):
|
||||||
tstr = t.encode('ascii', 'ignore')
|
tstr = t.encode('ascii', 'ignore')
|
||||||
if tstr in keywords:
|
if tstr in keywords:
|
||||||
raise ParseException, "Restricted keyword: %s" % (tstr,)
|
raise ParseException("Restricted keyword: %s" % (tstr,))
|
||||||
elif isinstance(t, str):
|
elif isinstance(t, str):
|
||||||
if t in keywords:
|
if t in keywords:
|
||||||
raise ParseException, "Restricted keyword: %s" % (t,)
|
raise ParseException("Restricted keyword: %s" % (t,))
|
||||||
|
|
||||||
disallow_keywords.keywords = set('if,elseif,else,endif,try,except,finally,endtry,while,endwhile,continue,break,for,foreach,endfor'.split(','))
|
disallow_keywords.keywords = set('if,elseif,else,endif,try,except,finally,endtry,while,endwhile,continue,break,for,foreach,endfor'.split(','))
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ class VMObjRef(VMType):
|
||||||
elif isinstance(value, (float, int)):
|
elif isinstance(value, (float, int)):
|
||||||
self.value = int(value)
|
self.value = int(value)
|
||||||
else:
|
else:
|
||||||
raise TypeError, "Attempted to create VMObjRef with invalid object reference: %r" % (value,)
|
raise TypeError("Attempted to create VMObjRef with invalid object reference: %r" % (value,))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@tokenparser
|
@tokenparser
|
||||||
|
|
|
@ -159,14 +159,14 @@ class Listener(object):
|
||||||
connid = random.randint(1, 65535)
|
connid = random.randint(1, 65535)
|
||||||
|
|
||||||
if not connid in self.connections:
|
if not connid in self.connections:
|
||||||
print "%s connected from %s" % (connid, addr)
|
print("%s connected from %s" % (connid, addr))
|
||||||
self.connections[connid] = Connection(connid, conn, addr)
|
self.connections[connid] = Connection(connid, conn, addr)
|
||||||
self.connection_list_dirty = True
|
self.connection_list_dirty = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def delete_connection(self, conn):
|
def delete_connection(self, conn):
|
||||||
print "%s disconnected." % (conn.id,)
|
print("%s disconnected." % (conn.id,))
|
||||||
del self.connections[conn.id]
|
del self.connections[conn.id]
|
||||||
self.remove_from_poller.append(conn.conn)
|
self.remove_from_poller.append(conn.conn)
|
||||||
self.connection_list_dirty = True
|
self.connection_list_dirty = True
|
||||||
|
@ -233,7 +233,7 @@ class Listener(object):
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
l = Listener()
|
l = Listener()
|
||||||
l.listen("", 7878)
|
l.listen("", 7878)
|
||||||
print "Listening on %s:%d" % (l.bind_addr, l.bind_port)
|
print("Listening on %s:%d" % (l.bind_addr, l.bind_port))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
|
|
102
netdoc.txt
Normal file
102
netdoc.txt
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
NETWORKING DETAILS
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
As a primarily network-driven multi-user environment, networking is fundamental to the general
|
||||||
|
operation of the server. This document will review the expected usage scenarios with the intent of
|
||||||
|
providing an overview of how the networking will typically work.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
~~~~~~~~~~~
|
||||||
|
It will help to define a few terms that will be used frequently:
|
||||||
|
|
||||||
|
server
|
||||||
|
The long running process which handles all oprtations
|
||||||
|
connection
|
||||||
|
A TCP network connection, typically established from a client to the server, but also applies
|
||||||
|
to outbound connections the server establishes.
|
||||||
|
listener
|
||||||
|
An object which has a listening port assigned to it, which will be notified of incoming
|
||||||
|
connections via that port.
|
||||||
|
object
|
||||||
|
An already existing object in the database.
|
||||||
|
connection id
|
||||||
|
A randomly generated numeric identifier that uniquely identifies a connection for its entire
|
||||||
|
duration and lifetime
|
||||||
|
assigned connection
|
||||||
|
A connection becomes officially "assigned" once it has been assigned from the listener to an
|
||||||
|
in-database object of its own.
|
||||||
|
assigning
|
||||||
|
While a connection starts as just a numeric id, in most cases it will eventually be assigned
|
||||||
|
to an in-database object so it can be tracked more obviously and interacted with more easily.
|
||||||
|
player
|
||||||
|
A specific type of object intended to have a user interactively connected to it, able to
|
||||||
|
execute actions within the server and is usually the primary interface to most servers.
|
||||||
|
|
||||||
|
PORT LISTENING
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
Except in very specialized situations, the server should always be listening on at least one
|
||||||
|
network port. Each listening port must be assigned a corresponding object in the database, known as
|
||||||
|
a listener object. This object will be expected to have various functions to handle incoming
|
||||||
|
connections.
|
||||||
|
|
||||||
|
TYPICAL CONFIGURATION
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
In a typical setup, the server will listen on an arbitrary high-numbered port (7777 is traditional)
|
||||||
|
and this port will be assigned a listener object of #0, the default system object. The system object
|
||||||
|
will provide functions that displays a login page or splash screen on initial connection as well as
|
||||||
|
being able to interpret basic commands. At some point, the remote connection will be expected to
|
||||||
|
provide a name and password that will allow them to login at which point their connection will be
|
||||||
|
reassigned from #0 to the selected user's player object.
|
||||||
|
|
||||||
|
TCP connections will normally be assumed, but allowing UDP connections will be a goal as well.
|
||||||
|
|
||||||
|
INCOMING CONNECTION
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
When a connection is first received, it will be assigned an arbitrary, randomized connection id.
|
||||||
|
Most likely to be implemented as an integer. This connection id will persist for the life of the
|
||||||
|
connection and will not change unless the connection is dropped and a new connection is established,
|
||||||
|
which is considered a new connection in all respects and is thus assigned a new connection id.
|
||||||
|
|
||||||
|
The connection id (assigned by the server) will be passed to the "initial_connection" function on
|
||||||
|
the appropriate listener object, based on the port the new connection is coming through.
|
||||||
|
|
||||||
|
Although the connection will be initialized in a default state, the initial_connection function is
|
||||||
|
expected to immediately assign any connection options it wishes and make any necessary preparations
|
||||||
|
to be ready to immediately begin receiving data from the connection. As long as the
|
||||||
|
initial_connection function does this without suspending or any other delay, it can be expected
|
||||||
|
that the assigned options will take effect before any data from the connection is processed.
|
||||||
|
|
||||||
|
Depending on the needs of the connection or protocol, it is acceptable for the initial_connection
|
||||||
|
function to send or attempt to receive data from the incoming connection. For example, a port 7777
|
||||||
|
connection may be immediately presented with a login splash screen.
|
||||||
|
|
||||||
|
CONNECTION CONFIGURATION
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
The connection can be configured in two basic modes: data mode and command mode. Data mode, the
|
||||||
|
default configuration, treats the connection as a basic IO pipe, with little interpretation done to
|
||||||
|
the data being sent or received. There will be no automatic reaction to data sent by the connection.
|
||||||
|
|
||||||
|
Command mode allows the connection to take advantage of the server's normal command processing
|
||||||
|
routines. Input will be automatically interpreted in the usual way that it is for players, even if
|
||||||
|
the connection is not yet assigned to a player object. For more details on the specifics of command
|
||||||
|
processing, please review commanddoc.txt
|
||||||
|
|
||||||
|
Traditionally, a connection will be switched to command mode once it is assigned, which will allow
|
||||||
|
it to interact with the objects and command functions in an interactive fashion. However, if so
|
||||||
|
desired it can instead be set to data mode and in this case the object it is connected to will act
|
||||||
|
like a private "listener" object specifically for that connection and will be able to interact with
|
||||||
|
the connection in the same way as a listener does. For many protocols this may make more sense.
|
||||||
|
Alternately, the connection can simply not be assigned to an object at all and instead remain on
|
||||||
|
the port listener object.
|
||||||
|
|
||||||
|
CONNECTION ASSIGNMENT
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Once an appropriate object has been selected for the unassigned connection, it can be assigned to
|
||||||
|
that object at any point. The appropriate object may be selected by, for example, matching the
|
||||||
|
credentials provided by the unassigned connection, or by selecting an object out of a pool of
|
||||||
|
placeholders arbitrarily, or by creating a new object from scratch, depending on the application.
|
||||||
|
|
||||||
|
To assign the connection, the built-in function "assign_connection" can be used.
|
||||||
|
|
||||||
|
|
||||||
|
Once the initial connection id has been configured, it is ready for low level IO only until it has
|
||||||
|
been assigned to an object.
|
|
@ -48,7 +48,7 @@ def optimize(data):
|
||||||
|
|
||||||
for x in data:
|
for x in data:
|
||||||
if not hasattr(x, "pos"):
|
if not hasattr(x, "pos"):
|
||||||
print "Missing position on element %s" % (x,)
|
print("Missing position on element %s" % (x,))
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
10
parse.py
10
parse.py
|
@ -172,9 +172,9 @@ class Parser(object):
|
||||||
|
|
||||||
endl.setParseAction(DiscardStack.parse)
|
endl.setParseAction(DiscardStack.parse)
|
||||||
self.parser = block
|
self.parser = block
|
||||||
#print argspec.parseString("hello(hi.xyz)", parseAll=True)
|
#print(argspec.parseString("hello(hi.xyz)", parseAll=True))
|
||||||
#print block.parseString(u"hi.xyz + #555.test;", parseAll=True)
|
#print(block.parseString(u"hi.xyz + #555.test;", parseAll=True))
|
||||||
#print block.parseString("""serverlog();""")
|
#print(block.parseString("""serverlog();"""))
|
||||||
|
|
||||||
def parse(self, data):
|
def parse(self, data):
|
||||||
rv = self.parser.parseString(data, parseAll=True)
|
rv = self.parser.parseString(data, parseAll=True)
|
||||||
|
@ -195,11 +195,11 @@ class Parser(object):
|
||||||
return [cmd, vars]
|
return [cmd, vars]
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
#print self.parse(u"if (1) #740.xyz + -hello.world; endif")
|
#print(self.parse(u"if (1) #740.xyz + -hello.world; endif"))
|
||||||
|
|
||||||
data = unicode(open("test.moo", "r").read(), 'utf-8')
|
data = unicode(open("test.moo", "r").read(), 'utf-8')
|
||||||
rv = self.parse(data)
|
rv = self.parse(data)
|
||||||
print rv
|
print(rv)
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
|
14
pbkdf2.py
14
pbkdf2.py
|
@ -82,13 +82,13 @@ def test():
|
||||||
def check(data, salt, iterations, keylen, expected):
|
def check(data, salt, iterations, keylen, expected):
|
||||||
rv = pbkdf2_hex(data, salt, iterations, keylen)
|
rv = pbkdf2_hex(data, salt, iterations, keylen)
|
||||||
if rv != expected:
|
if rv != expected:
|
||||||
print 'Test failed:'
|
print('Test failed:')
|
||||||
print ' Expected: %s' % expected
|
print(' Expected: %s' % expected)
|
||||||
print ' Got: %s' % rv
|
print(' Got: %s' % rv)
|
||||||
print ' Parameters:'
|
print(' Parameters:')
|
||||||
print ' data=%s' % data
|
print(' data=%s' % data)
|
||||||
print ' salt=%s' % salt
|
print(' salt=%s' % salt)
|
||||||
print ' iterations=%d' % iterations
|
print(' iterations=%d' % iterations)
|
||||||
print
|
print
|
||||||
failed.append(1)
|
failed.append(1)
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ class RingBuffer(object):
|
||||||
|
|
||||||
def rewind(self, bytes):
|
def rewind(self, bytes):
|
||||||
if bytes > self.read_pos:
|
if bytes > self.read_pos:
|
||||||
raise ValueError, "Buffer is not big enough to rewind that far"
|
raise ValueError("Buffer is not big enough to rewind that far")
|
||||||
|
|
||||||
self.read_pos -= bytes
|
self.read_pos -= bytes
|
||||||
if bytes > 0:
|
if bytes > 0:
|
||||||
|
@ -85,7 +85,7 @@ class SplitRingBuffer(RingBuffer):
|
||||||
|
|
||||||
class RingBufferFull(object):
|
class RingBufferFull(object):
|
||||||
def __init__(self, size):
|
def __init__(self, size):
|
||||||
raise NotImplementedError, "You should not create this class manually, use RingBuffer() instead"
|
raise NotImplementedError("You should not create this class manually, use RingBuffer() instead")
|
||||||
|
|
||||||
def overflow_buffer():
|
def overflow_buffer():
|
||||||
self.buffer_pos = 0
|
self.buffer_pos = 0
|
||||||
|
@ -172,7 +172,7 @@ class RingBufferFull(object):
|
||||||
|
|
||||||
def rewind(self, bytes):
|
def rewind(self, bytes):
|
||||||
if bytes > self.sizeleft():
|
if bytes > self.sizeleft():
|
||||||
raise ValueError, "Buffer is not big enough to rewind that far"
|
raise ValueError("Buffer is not big enough to rewind that far")
|
||||||
|
|
||||||
self.read_pos -= bytes
|
self.read_pos -= bytes
|
||||||
if self.read_pos < 0:
|
if self.read_pos < 0:
|
||||||
|
|
|
@ -50,7 +50,7 @@ class Server(object):
|
||||||
if ds[-1] == '':
|
if ds[-1] == '':
|
||||||
del ds[-1]
|
del ds[-1]
|
||||||
for line in ds:
|
for line in ds:
|
||||||
print "%s: %s" % (conn.id, line)
|
print("%s: %s" % (conn.id, line))
|
||||||
cmd, vars = static_parser.parse_command(line)
|
cmd, vars = static_parser.parse_command(line)
|
||||||
self.db.match_command(cmd, vars)
|
self.db.match_command(cmd, vars)
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,7 @@ class VirtualMachine(object):
|
||||||
|
|
||||||
def uncaught_exception(self):
|
def uncaught_exception(self):
|
||||||
for exc in self.task.exc_stack:
|
for exc in self.task.exc_stack:
|
||||||
print "Unhandled exception: %s" % (exc,)
|
print("Unhandled exception: %s" % (exc,))
|
||||||
|
|
||||||
def run_active_task(self):
|
def run_active_task(self):
|
||||||
task_id = self.active_task_id
|
task_id = self.active_task_id
|
||||||
|
@ -238,7 +238,7 @@ class VirtualMachine(object):
|
||||||
self.uncaught_exception()
|
self.uncaught_exception()
|
||||||
self.finished_start_next()
|
self.finished_start_next()
|
||||||
else:
|
else:
|
||||||
print "executing %s with stack %s" % (op, self.task.stack)
|
print("executing %s with stack %s" % (op, self.task.stack))
|
||||||
#op.load_stack(self)
|
#op.load_stack(self)
|
||||||
op.execute(self)
|
op.execute(self)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue