diff --git a/.settings.dist.yaml b/.settings.dist.yaml deleted file mode 100644 index 2fbdf3a..0000000 --- a/.settings.dist.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Copy this to .settings.yaml and fill it out. - -# Screeps account info -# Your username is your full email address. -screeps_username: -screeps_password: -screeps_ptr: false - -# Set a hostname to connect to a private server (e.g. localhost:21025) -screeps_host: - -# Proxy configuration -http_proxy: -http_proxy_port: - - -# Introduces a small delay between messages to emulate smooth scrolling. -smooth_scroll: true - -# Once the output buffer reaches this length it will start removing old messages -max_scroll: 200000 - -# Defines the maximum commands saved to the history file -max_history: 200000 diff --git a/README.md b/README.md index e44f451..245766c 100644 --- a/README.md +++ b/README.md @@ -24,61 +24,75 @@ Note: This application requires Python 2, not 3. 1. Determine where your Python is installed with `which python` - assume it is `/path/to/python` and replace that below 1. Set up the `virtualenv` with the command `virtualenv -p /path/to/python env` 1. Use that new `virtualenv` with the command `source env/bin/activate` -2. Run `make` -3. Run `make install` -4. Create settings (as per the instructions below) -5. Run `screepsconsole` from inside the terminal +1. Run `make` +1. Run `make install` +1. Run `screepsconsole` from inside the terminal ## Settings -The settings file is a yaml file. Begin by copying the settings.dist file to -.settings.yaml in the directory you will be calling the shell from, or you can -store the file in your home directory. +The settings file is created automatically and placed in `~.screepsconsole.yaml`. +Typically there is little reason to edit it manually. When you attempt to connect +to a server for the first time it will ask for your credentials (and if it's a +private server for the host), which will then be saved for future use. + + +## Launching + +The interactive shell can be used for both reading console output and sending +console commands to the server. + +```bash +$ screepsconsole +``` + +By default it connects to the main server, but it can also connect to PTR. + +```bash +$ screepsconsole ptr ``` -cp .settings.dist.yaml ~/.screeps_settings.yaml + +The system also works with private servers. Any label can be used, and unlike +the main server the system will ask for a host (include the port) and whether +the shard uses https. + +```bash +$ screepsconsole screepsplus ``` -The settings file is in yaml and takes various authentication tokens. +It is possible to clear a saved connection. -```yaml -# Copy this to .settings.yaml and fill it out. +```bash +$ screepsconsole clear connectionname +``` -# Screeps account info -# Your username is your full email address. -screeps_username: -screeps_password: -screeps_ptr: false +You can also call the python script directly. -# Proxy configuration -http_proxy: -http_proxy_port: +```bash +$ ./screeps_console/interactive.py ``` -## Launching +## Streaming Console -To stream the console output directly to your terminal's stdout run the -`console.py` application. +To stream the console output directly to your terminal's stdout without the +ability to send command use the `console.py` application. ```bash $ ./screeps_console/console.py ``` -This project also offers an interactive shell that can be used for both reading -console output and sending console commands to the server. - -If you've installed using the provided make file you can launch +Like the Interactive version different servers can be specified. ```bash -$ screepsconsole +$ ./screeps_console/console.py ptr ``` -You can also call the python script directly. +The output can also be sent in JSON. ```bash -$ ./screeps_console/interactive.py +$ ./screeps_console/console.py main json ``` diff --git a/screeps_console/command.py b/screeps_console/command.py index 68c352e..1229cba 100644 --- a/screeps_console/command.py +++ b/screeps_console/command.py @@ -1,8 +1,7 @@ from autocomplete import Autocomplete import calendar -import screepsapi -from settings import getSettings +import settings import re from themes import themes import time @@ -19,7 +18,8 @@ class Processor(object): 'help': 'list' } - def __init__(self): + def __init__(self, connectionname): + self.connectionname = connectionname self.lastkeytime = 0 self.listbox = False self.listwalker = False @@ -28,6 +28,7 @@ def __init__(self): self.getApiClient() self.autocomplete = Autocomplete(self) + def setDisplayWidgets(self, loop, frame, listbox, listwalker, edit, consolemonitor): self.listbox = listbox # console self.listwalker = listwalker @@ -35,15 +36,10 @@ def setDisplayWidgets(self, loop, frame, listbox, listwalker, edit, consolemonit self.loop = loop self.consolemonitor = consolemonitor + def getApiClient(self): - if not self.apiclient: - settings = getSettings() - self.apiclient = screepsapi.API( - u=settings['screeps_username'], - p=settings['screeps_password'], - ptr=settings['screeps_ptr'], - host=settings['screeps_host']) - return self.apiclient + return settings.getApiClient(self.connectionname) + def onInput(self, key): @@ -86,6 +82,7 @@ def onInput(self, key): return + def onEnter(self, key): self.listbox.setAutoscroll(True) userInput = self.edit diff --git a/screeps_console/console.py b/screeps_console/console.py index 60a39ee..d56543b 100755 --- a/screeps_console/console.py +++ b/screeps_console/console.py @@ -7,7 +7,7 @@ from outputparser import parseLine from outputparser import tagLine import screepsapi -from settings import getSettings +import settings from time import sleep import websocket from StringIO import StringIO @@ -43,7 +43,6 @@ def on_message(self, ws, message): except: print("Unexpected error:", sys.exc_info()) return - data = json.loads(message) if 'shard' in data[1]: @@ -66,8 +65,9 @@ def on_message(self, ws, message): message_count = len(stream) if message_count > 0: + config = settings.getSettings() # Make sure the delay doesn't cause an overlap into other ticks - if 'smooth_scroll' in settings and settings['smooth_scroll'] is True: + if 'smooth_scroll' in config and config['smooth_scroll'] is True: message_delay = 0.2 / message_count if message_delay > 0.07: message_delay = 0.07 @@ -111,14 +111,18 @@ def start(self): if __name__ == "__main__": - opts, args = getopt.getopt(sys.argv[1:], "hi:o:",["ifile=","ofile="]) - settings = getSettings() - screepsconsole = ScreepsConsole(user=settings['screeps_username'], password=settings['screeps_password'], ptr=settings['screeps_ptr'], host=settings['screeps_host']) + if len(sys.argv) < 2: + server = 'main' + else: + server = sys.argv[1] + + config = settings.getConnection(server) + screepsconsole = ScreepsConsole(user=config['username'], password=config['password'], secure=config['secure'], host=config['host']) - if len(sys.argv) > 1: - if sys.argv[1] == 'interactive': + if len(sys.argv) > 2: + if sys.argv[2] == 'interactive': screepsconsole.format = 'tag' - if sys.argv[1] == 'json': + if sys.argv[2] == 'json': screepsconsole.format = 'json' screepsconsole.start() diff --git a/screeps_console/interactive.py b/screeps_console/interactive.py index 89d7c6b..5cb2240 100755 --- a/screeps_console/interactive.py +++ b/screeps_console/interactive.py @@ -8,7 +8,7 @@ from os.path import expanduser import outputparser import re -from settings import getSettings +import settings import signal import subprocess import sys @@ -23,15 +23,17 @@ class ScreepsInteractiveConsole: userInput = False consoleMonitor = False - def __init__(self): + def __init__(self, connection_name): try: + self.connection_name = connection_name frame = self.getFrame() comp = self.getCommandProcessor() self.loop = urwid.MainLoop(urwid.AttrMap(frame, 'bg'), unhandled_input=comp.onInput, palette=themes['dark']) - self.consoleMonitor = ScreepsConsoleMonitor(self.consoleWidget, + self.consoleMonitor = ScreepsConsoleMonitor(connection_name, + self.consoleWidget, self.listWalker, self.loop) @@ -56,7 +58,6 @@ def getFrame(self): return frame_widget - def getHeader(self): return urwid.AttrMap(urwid.Text("Screeps Interactive Console", align='center'), 'header') @@ -73,16 +74,16 @@ def getConsole(self): def getConsoleListWalker(self): if not self.listWalker: self.listWalker = consoleWalker([self.getWelcomeMessage()]) - settings = getSettings() - if 'max_buffer' in settings: - self.listWalker.max_buffer = settings['max_buffer'] + config = settings.getSettings() + if 'max_buffer' in config: + self.listWalker.max_buffer = config['max_buffer'] else: self.listWalker.max_buffer = 200000 return self.listWalker def getCommandProcessor(self): - return command.Processor() + return command.Processor(self.connection_name) def getWelcomeMessage(self): return urwid.Text(('default', 'Welcome to the Screeps Interactive Console')) @@ -167,9 +168,9 @@ def manageBufferHistory(self): file_contents = myfile.read() file_contents_line = file_contents.splitlines() num_lines = len(file_contents_line) - settings = getSettings() - if 'max_history' in settings: - max_scroll = settings['max_history'] + config = settings.getSettings() + if 'max_history' in config: + max_scroll = config['max_history'] else: max_scroll = 200000 @@ -241,7 +242,8 @@ class ScreepsConsoleMonitor: focus = False filters = [] - def __init__(self, widget, walker, loop): + def __init__(self, connectionname, widget, walker, loop): + self.connectionname = connectionname self.widget = widget self.walker = walker self.loop = loop @@ -255,7 +257,7 @@ def getProcess(self): console_path = os.path.join(os.path.dirname(sys.argv[0]), 'console.py ') write_fd = self.loop.watch_pipe(self.onUpdate) self.proc = subprocess.Popen( - [console_path + ' json'], + [console_path + ' ' + self.connectionname + ' json'], stdout=write_fd, preexec_fn=os.setsid, close_fds=True, @@ -366,4 +368,46 @@ def __del__(self): if __name__ == "__main__": - ScreepsInteractiveConsole() + + if len(sys.argv) < 2: + server = 'main' + else: + server = sys.argv[1] + + if server == 'clear': + if len(sys.argv) < 3: + server = 'main' + else: + server = sys.argv[2] + settings.removeConnection(server) + sys.exit(0) + + connectionSettings = settings.getConnection(server) + + if not connectionSettings: + if server == 'main' or server == 'ptr': + legacyConfig = settings.getLegacySettings() + if legacyConfig: + if raw_input("Upgrade settings file to the new format? (y/n) ") != "y": + sys.exit(-1) + settings.addConnection('main', legacyConfig['screeps_username'], legacyConfig['screeps_password']) + config = settings.getSettings() + config['smooth_scroll'] = legacyConfig['smooth_scroll'] + config['max_scroll'] = legacyConfig['max_scroll'] + config['max_history'] = legacyConfig['max_history'] + settings.saveSettings(config) + connectionSettings = settings.getConnection(server) + + if not connectionSettings: + if server is 'main': + host = 'screeps.com' + secure = True + else: + host = raw_input("Host: ") + secure = raw_input("Secure (y/n) ") == "y" + username = raw_input("Username: ") + password = raw_input("Password: ") + settings.addConnection(server, username, password, host, secure) + + + ScreepsInteractiveConsole(server) diff --git a/screeps_console/settings.py b/screeps_console/settings.py index 5686121..03c993a 100644 --- a/screeps_console/settings.py +++ b/screeps_console/settings.py @@ -2,10 +2,101 @@ from os.path import expanduser import sys import yaml +import screepsapi + + +userhome = expanduser('~') +settingsfile = userhome + '/.screepsconsole.yaml' def getSettings(): - if not getSettings.settings: + if not os.path.isfile(settingsfile): + settings = { + 'connections': {}, + 'max_history': 200000, + 'max_scroll': 200000, + 'smooth_scroll': True + } + saveSettings(settings) + return settings + with open(settingsfile, 'r') as f: + settings = yaml.load(f) + return settings + + +def getConnection(name): + settings = getSettings() + + if not settings: + return False + + if 'connections' not in settings: + return False + + if name not in settings['connections']: + return False + + return settings['connections'][name] + + +def addConnection(name, username, password, host=False, secure=False): + if name == 'main': + secure = True + host = 'screeps.com' + addConnection('ptr', username, password) + if name == 'ptr': + secure = True + host = 'screeps.com/ptr' + + settings = getSettings() + if not settings: + settings = {} + + if 'connections' not in settings: + settings['connections'] = {} + + settings['connections'][name] = { + 'host': host, + 'secure': secure, + 'username': username, + 'password': password + } + + saveSettings(settings) + + +def removeConnection(name): + if name == 'main': + removeConnection('ptr') + if not getConnection(name): + return False + config = getSettings() + del config['connections'][name] + saveSettings(config) + + +def saveSettings(settings): + with open(settingsfile, 'w') as outfile: + yaml.dump(settings, outfile, default_flow_style=False) + + +def getApiClient(name): + settings = getConnection(name) + return screepsapi.API( + u=settings['username'], + p=settings['password'], + host=settings['host'], + secure=settings['secure'], + ) + + + + + + + +def getLegacySettings(): + if not getLegacySettings.settings: cwd = os.getcwd() path = cwd + '/.settings.yaml' @@ -16,13 +107,11 @@ def getSettings(): path = expanduser('~') + '/.screeps_settings.yaml' if not os.path.isfile(path): - print 'no settings file found' - sys.exit(-1) return False with open(path, 'r') as f: - getSettings.settings = yaml.load(f) + getLegacySettings.settings = yaml.load(f) - return getSettings.settings + return getLegacySettings.settings -getSettings.settings = False +getLegacySettings.settings = False