From 0b3c747e9348f463c0da7aad03939b67ca4faabe Mon Sep 17 00:00:00 2001 From: cecilkorik Date: Tue, 23 Apr 2019 14:17:11 -0400 Subject: [PATCH] python 3 conversion included missing language_tools file fixed hgignore added documentation txt files --HG-- branch : mung --- builtins.py | 3 ++ builtins_code.py | 2 +- bytecode.py | 6 +-- dbdoc.txt | 3 ++ language_tools.py | 2 +- language_types.py | 8 ++-- listener.py | 6 +-- netdoc.txt | 102 ++++++++++++++++++++++++++++++++++++++++++++++ optimizer.py | 2 +- parse.py | 10 ++--- pbkdf2.py | 14 +++---- ringbuffer.py | 6 +-- server.py | 2 +- virtualmachine.py | 4 +- 14 files changed, 139 insertions(+), 31 deletions(-) create mode 100644 dbdoc.txt create mode 100644 netdoc.txt diff --git a/builtins.py b/builtins.py index c5dc5b8..8285bba 100755 --- a/builtins.py +++ b/builtins.py @@ -1,4 +1,7 @@ from builtins_code import bi + +__all__ = ['builtin_map'] + builtin_map = {} diff --git a/builtins_code.py b/builtins_code.py index ab739b6..e92edc9 100755 --- a/builtins_code.py +++ b/builtins_code.py @@ -5,7 +5,7 @@ class builtin_functions(object): @staticmethod def serverlog(vm, args): - print "server_log: %s" % (args,) + print("server_log: %s" % (args,)) @staticmethod def create(vm, args): diff --git a/bytecode.py b/bytecode.py index 186f1c4..4954c90 100644 --- a/bytecode.py +++ b/bytecode.py @@ -6,7 +6,7 @@ import optimizer def coerce(value): - from language_types import * + from language_types import VMInteger, VMList, VMString, VMTable, VMObjRef, VMFloat, VMType if isinstance(value, int): return VMInteger(value) elif isinstance(value, (tuple, list)): @@ -165,7 +165,7 @@ class CallBuiltin(CodeOp): @tokenparser def parse(tokens): #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()) class CallFunction(CodeOp): @@ -319,7 +319,7 @@ class Assignment(CodeOp): elif isinstance(var, VMFileRef): var = var.ref() + [SetFile()] else: - raise ValueError, "Assignment to unknown type: %s" % (var,) + raise ValueError("Assignment to unknown type: %s" % (var,)) return codejoin(tokens[2:], var) return tokens diff --git a/dbdoc.txt b/dbdoc.txt new file mode 100644 index 0000000..48b4ee0 --- /dev/null +++ b/dbdoc.txt @@ -0,0 +1,3 @@ +DATABASE FORMAT SPECIFICATION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + diff --git a/language_tools.py b/language_tools.py index 514b7df..0d03377 100644 --- a/language_tools.py +++ b/language_tools.py @@ -24,7 +24,7 @@ def tokenparser(func): for x in gd: if hasattr(gd[x], "parse") and gd[x].parse == newfunc: funcobj = x - print "Error with %s.parse tokens: %s" % (funcobj, tokens) + print("Error with %s.parse tokens: %s" % (funcobj, tokens)) traceback.print_exc(e) raise diff --git a/language_types.py b/language_types.py index 52c5abd..7eeb111 100755 --- a/language_types.py +++ b/language_types.py @@ -11,14 +11,14 @@ def disallow_keywords(tokens,keywords=None): for t in tokens: if isinstance(t, VMIdent): if t.name in keywords: - raise ParseException, "Restricted keyword: %s" % (t.name,) + raise ParseException("Restricted keyword: %s" % (t.name,)) elif isinstance(t, unicode): tstr = t.encode('ascii', 'ignore') if tstr in keywords: - raise ParseException, "Restricted keyword: %s" % (tstr,) + raise ParseException("Restricted keyword: %s" % (tstr,)) elif isinstance(t, str): 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(',')) @@ -119,7 +119,7 @@ class VMObjRef(VMType): elif isinstance(value, (float, int)): self.value = int(value) 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 @tokenparser diff --git a/listener.py b/listener.py index cae1d03..6fa6082 100644 --- a/listener.py +++ b/listener.py @@ -159,14 +159,14 @@ class Listener(object): connid = random.randint(1, 65535) 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.connection_list_dirty = True break def delete_connection(self, conn): - print "%s disconnected." % (conn.id,) + print("%s disconnected." % (conn.id,)) del self.connections[conn.id] self.remove_from_poller.append(conn.conn) self.connection_list_dirty = True @@ -233,7 +233,7 @@ class Listener(object): if __name__ == "__main__": l = Listener() 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: while True: diff --git a/netdoc.txt b/netdoc.txt new file mode 100644 index 0000000..906c536 --- /dev/null +++ b/netdoc.txt @@ -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. \ No newline at end of file diff --git a/optimizer.py b/optimizer.py index 5b040c8..f695a40 100755 --- a/optimizer.py +++ b/optimizer.py @@ -48,7 +48,7 @@ def optimize(data): for x in data: if not hasattr(x, "pos"): - print "Missing position on element %s" % (x,) + print("Missing position on element %s" % (x,)) return data \ No newline at end of file diff --git a/parse.py b/parse.py index 1923f79..a4a01ec 100755 --- a/parse.py +++ b/parse.py @@ -172,9 +172,9 @@ class Parser(object): endl.setParseAction(DiscardStack.parse) self.parser = block - #print argspec.parseString("hello(hi.xyz)", parseAll=True) - #print block.parseString(u"hi.xyz + #555.test;", parseAll=True) - #print block.parseString("""serverlog();""") + #print(argspec.parseString("hello(hi.xyz)", parseAll=True)) + #print(block.parseString(u"hi.xyz + #555.test;", parseAll=True)) + #print(block.parseString("""serverlog();""")) def parse(self, data): rv = self.parser.parseString(data, parseAll=True) @@ -195,11 +195,11 @@ class Parser(object): return [cmd, vars] 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') rv = self.parse(data) - print rv + print(rv) return rv diff --git a/pbkdf2.py b/pbkdf2.py index 532244e..624c7e4 100644 --- a/pbkdf2.py +++ b/pbkdf2.py @@ -82,13 +82,13 @@ def test(): def check(data, salt, iterations, keylen, expected): rv = pbkdf2_hex(data, salt, iterations, keylen) if rv != expected: - print 'Test failed:' - print ' Expected: %s' % expected - print ' Got: %s' % rv - print ' Parameters:' - print ' data=%s' % data - print ' salt=%s' % salt - print ' iterations=%d' % iterations + print('Test failed:') + print(' Expected: %s' % expected) + print(' Got: %s' % rv) + print(' Parameters:') + print(' data=%s' % data) + print(' salt=%s' % salt) + print(' iterations=%d' % iterations) print failed.append(1) diff --git a/ringbuffer.py b/ringbuffer.py index 6bf5319..ef02c96 100755 --- a/ringbuffer.py +++ b/ringbuffer.py @@ -60,7 +60,7 @@ class RingBuffer(object): def rewind(self, bytes): 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 if bytes > 0: @@ -85,7 +85,7 @@ class SplitRingBuffer(RingBuffer): class RingBufferFull(object): 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(): self.buffer_pos = 0 @@ -172,7 +172,7 @@ class RingBufferFull(object): def rewind(self, bytes): 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 if self.read_pos < 0: diff --git a/server.py b/server.py index 72481c8..3889bea 100644 --- a/server.py +++ b/server.py @@ -50,7 +50,7 @@ class Server(object): if ds[-1] == '': del ds[-1] for line in ds: - print "%s: %s" % (conn.id, line) + print("%s: %s" % (conn.id, line)) cmd, vars = static_parser.parse_command(line) self.db.match_command(cmd, vars) diff --git a/virtualmachine.py b/virtualmachine.py index 8348aa5..f075432 100755 --- a/virtualmachine.py +++ b/virtualmachine.py @@ -170,7 +170,7 @@ class VirtualMachine(object): def uncaught_exception(self): for exc in self.task.exc_stack: - print "Unhandled exception: %s" % (exc,) + print("Unhandled exception: %s" % (exc,)) def run_active_task(self): task_id = self.active_task_id @@ -238,7 +238,7 @@ class VirtualMachine(object): self.uncaught_exception() self.finished_start_next() 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.execute(self)