ソースを参照

Updated: working port report parse + cycle.

Steve Thielemann 5 年 前
コミット
5ed4afbb56
1 ファイル変更151 行追加8 行削除
  1. 151 8
      tcp-proxy.py

+ 151 - 8
tcp-proxy.py

@@ -13,6 +13,7 @@ import pendulum
 from subprocess import check_output
 
 from colorama import Fore, Back, Style
+from itertools import cycle
 
 # This isn't the best configuration, but it's simple
 # and works.  Mostly.
@@ -126,19 +127,37 @@ class MCP(object):
         self.prompt = None
         self.observer = None
         self.keepalive = None
+        # Port Data
+        self.portdata = None
+        self.portcycle = None
 
     def finishSetup(self):
-        if self.queue_game is None:
-            self.queue_game = self.game.queue_game
-        if self.observer is None:
-            self.observer = self.game.observer
+        # if self.queue_game is None:
+        self.queue_game = self.game.queue_game
+        # if self.observer is None:
+        self.observer = self.game.observer
         self.observer.connect("hotkey", self.activate)
+        self.observer.connect("notyet", self.notyet)
+
+    def notyet(self, _):
+        """ No, not yet! """
+        nl = "\n\r"
+        r = Style.RESET_ALL
+
+        log.msg("NNY!")
+        prompt = self.game.buffer
+        self.queue_game.put(r + nl + "Proxy: I can't activate at this time." + nl)
+        self.queue_game.put(prompt)
 
     def stayAwake(self):
         """ Send a space to the game to keep it alive/don't timeout. """
         log.msg("Gameserver, stay awake.")
         self.game.queue_player.put(" ")
 
+    def startAwake(self):
+        self.keepalive = task.LoopingCall(self.stayAwake)
+        self.keepalive.start(30)
+
     def activate(self, _):
         log.msg("MCP menu called.")
         # We want the raw one, not the ANSI cleaned getPrompt.
@@ -153,8 +172,9 @@ class MCP(object):
         self.displayMenu()
         self.observer.connect("player", self.fromPlayer)
         # TODO:  Add background "keepalive" event so the game doesn't time out on us.
-        self.keepalive = task.LoopingCall(self.stayAwake)
-        self.keepalive.start(30)
+        self.startAwake()
+        # self.keepalive = task.LoopingCall(self.stayAwake)
+        # self.keepalive.start(30)
 
     def displayMenu(self):
         nl = "\n\r"
@@ -193,8 +213,14 @@ class MCP(object):
         elif key == "P":
             log.msg("Port")
             self.queue_game.put(c + key + r + nl)
-            self.queue_game.put(nl + c + "NO, NOT YET!" + r + nl)
+            self.portReport()
+            # self.queue_game.put(nl + c + "NO, NOT YET!" + r + nl)
+            # self.displayMenu()
+
+        elif key == 'D':
+            self.queue_game.put(nl + "Diagnostics" + nl "portdata:" + nl + repr(self.portdata) + nl)
             self.displayMenu()
+
         elif key == "X":
             log.msg('"Quit, return to "normal".  (Whatever that means!)')
             self.queue_game.put(c + key + r + nl)
@@ -204,12 +230,109 @@ class MCP(object):
             self.prompt = None
             self.keepalive.stop()
             self.keepalive = None
+            self.game.to_player = True
         else:
             if key.isprintable():
                 self.queue_game.put(r + nl)
                 self.queue_game.put("Excuse me? I don't understand '" + key + "'." + nl)
                 self.displayMenu()
 
+    def portReport(self):
+        """ Activate CIM and request Port Report """
+        self.game.to_player = False
+        self.portdata = None
+        self.observer.connect('prompt', self.portPrompt)
+        self.observer.connect('game-line', self.portParse)
+        self.game.queue_player.put("^")
+
+    def portPrompt(self, prompt):
+        if prompt == ': ':
+            log.msg("CIM Prompt")
+            if self.portdata is None:
+                log.msg("R - Port Report")
+                self.portdata = dict()
+                self.game.queue_player.put("R")
+                self.portcycle = cycle(['/', '-', '\\', '|'])
+                self.queue_game.put(' ')
+            else:
+                log.msg("Q - Quit")
+                self.game.queue_player.put("Q")
+                self.portcycle = None
+
+    def portBS(self, info):
+        if info[0] == '-':
+            bs = 'B'
+        else:
+            bs = 'S'
+        return (bs, int(info[1:].strip()))
+
+    def portParse(self, line):
+        if line == '':
+            return
+        if line == ': ':
+            return
+
+        log.msg("parse line:", line)
+
+        if line.startswith('Command [TL='):
+            return
+
+        if line == ': ENDINTERROG':
+            log.msg("CIM Done")
+            log.msg(self.portdata)
+            self.queue_game.put("\x08 \x08" + "\n\r")
+            self.observer.disconnect('prompt', self.portPrompt)
+            self.observer.disconnect('game-line', self.portParse)
+            self.game.to_player = True
+            # self.keepalive.start(30)
+            self.startAwake()
+            self.displayMenu()
+            return
+
+        # Give some sort of feedback to the user.
+        if self.portcycle:
+            self.queue_game.put("\x08" + next(self.portcycle))
+
+        # Ok, we need to parse this line
+        # 436   2870 100% - 1520 100% - 2820 100%
+        #    2   1950 100% - 1050 100%   2780 100% 
+        #    5   2800 100% - 2330 100% - 1230 100% 
+        #    8   2890 100%   1530 100% - 2310 100% 
+        #    9 - 2160 100%   2730 100% - 2120 100% 
+        #  324 - 2800 100%   2650 100% - 2490 100% 
+        #  492    990 100%    900 100%   1660 100% 
+        #  890   1920 100% - 2140 100%   1480 100% 
+        # 1229 - 2870 100% - 1266  90%    728  68% 
+        # 1643 - 3000 100% - 3000 100% - 3000 100% 
+        # 1683 - 1021  97%   1460 100% - 2620 100% 
+        # 1898 - 1600 100% - 1940 100% - 1860 100% 
+        # 2186   1220 100% -  900 100% - 1840 100% 
+        # 2194   2030 100% - 1460 100% - 1080 100% 
+        # 2577   2810 100% - 1550 100% - 2350 100% 
+        # 2629   2570 100% - 2270 100% - 1430 100% 
+        # 3659 - 1720 100%   1240 100% - 2760 100% 
+        # 3978 -  920 100%   2560 100% - 2590 100% 
+        # 4302    348  25% - 2530 100% -  316  23% 
+        # 4516 - 1231  60% - 1839  75%      7   0%
+        work = line.replace('%', '')
+        parts = re.split(r"(?<=\d)\s", work)
+        if len(parts) == 8:
+            port = int(parts[0].strip())
+            data = dict()
+            data['fuel'] = dict( )
+            data['fuel']['sale'], data['fuel']['units'] = self.portBS(parts[1])
+            data['fuel']['pct'] = int(parts[2].strip())
+            data['org'] = dict( )
+            data['org']['sale'], data['org']['units'] = self.portBS(parts[3])
+            data['org']['pct'] = int(parts[4].strip())
+            data['equ'] = dict( )
+            data['equ']['sale'], data['equ']['units'] = self.portBS(parts[5])
+            data['equ']['pct'] = int(parts[6].strip())
+            self.portdata[port] = data
+        else:
+            self.queue_game.put("?")
+            log.msg("Line in question is: [{0}].".format(line))
+            log.msg(repr(parts))
 
 class Game(protocol.Protocol):
     def __init__(self):
@@ -224,6 +347,7 @@ class Game(protocol.Protocol):
         self.queue_player = self.factory.queue_player
         self.queue_game = self.factory.queue_game
         self.observer = self.factory.observer
+        self.factory.game = self
         self.setPlayerReceived()
         self.observer.connect("user-game", self.show_game)
         self.mcp.finishSetup()
@@ -343,6 +467,7 @@ class GlueFactory(protocol.ClientFactory):
         self.queue_player = player.queue_player
         self.queue_game = player.queue_game
         self.observer = player.observer
+        self.game = None
 
     def closeIt(self):
         log.msg("closeIt")
@@ -371,6 +496,8 @@ class Player(protocol.Protocol):
         self.buffer = ""
         self.user = None
         self.observer = Observer()
+        self.game = None
+        self.glue = None
 
     def connectionMade(self):
         """ connected, setup queues. 
@@ -384,6 +511,7 @@ class Player(protocol.Protocol):
 
         # Connect GlueFactory to this Player object.
         factory = GlueFactory(self)
+        self.glue = factory
 
         # Make connection to the game server
         reactor.connectTCP(HOST, PORT, factory, 5)
@@ -394,6 +522,10 @@ class Player(protocol.Protocol):
 
     def gameDataReceived(self, chunk):
         """ Data received from the game. """
+        # If we have received game data, it has to be connected.
+        if self.game is None:
+            self.game = self.glue.game
+
         if chunk is False:
             self.transport.loseConnection()
         else:
@@ -428,10 +560,21 @@ class Player(protocol.Protocol):
             self.queue_player.put(chunk)
 
         if chunk == b"~":
+            if self.game:
+                prompt = self.game.getPrompt()
+                if "Selection (? for menu)" in prompt:
+                    self.observer.emit("notyet", prompt)
+                if "Enter your choice:" in prompt:
+                    self.observer.emit("notyet", prompt)
+                if re.match(r"Computer command \[TL=.* \(\?=Help\)\? :", prompt):
+                    self.observer.emit("notyet", prompt)
+                if re.match(r"Command \[TL=.* \(\?=Help\)\? :", prompt):
+                    self.observer.emit("hotkey", prompt)
+
             # Selection (? for menu):   (the game server menu)
             # Enter your choice:  (game menu)
             # Command [TL=00:00:00]:[1800] (?=Help)? :  <- YES!
-            self.observer.emit("hotkey", None)
+            # Computer command [TL=00:00:00]:[613] (?=Help)?
 
     def connectionLost(self, why):
         log.msg("lost connection %s" % why)