#!/usr/bin/env python3
import curses
-import socket
import queue
import threading
-from plomrogue.io_tcp import PlomSocket
from plomrogue.game import GameBase
from plomrogue.parser import Parser
from plomrogue.mapping import YX, MapGeometrySquare, MapGeometryHex
from plomrogue.things import ThingBase
from plomrogue.misc import quote
+from plomrogue.errors import BrokenSocketConnection
+
+from ws4py.client import WebSocketBaseClient
+class WebSocketClient(WebSocketBaseClient):
+
+ def __init__(self, recv_handler, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.recv_handler = recv_handler
+ self.connect()
+
+ def received_message(self, message):
+ if message.is_text:
+ message = str(message)
+ self.recv_handler(message)
+
+ @property
+ def plom_closed(self):
+ return self.client_terminated
+
+from plomrogue.io_tcp import PlomSocket
+class PlomSocketClient(PlomSocket):
+
+ def __init__(self, recv_handler, url):
+ import socket
+ self.recv_handler = recv_handler
+ host, port = url.split(':')
+ super().__init__(socket.create_connection((host, port)))
+
+ def close(self):
+ self.socket.close()
+
+ def run(self):
+ try:
+ for msg in self.recv():
+ self.recv_handler(msg)
+ except BrokenSocketConnection:
+ pass # we assume socket will be known as dead by now
def cmd_TURN(game, n):
game.turn = n
game.map_content = content
if type(game.map_geometry) == MapGeometrySquare:
game.tui.movement_keys = {
- 'w': 'UP',
- 'a': 'LEFT',
- 's': 'DOWN',
- 'd': 'RIGHT',
+ game.tui.keys['square_move_up']: 'UP',
+ game.tui.keys['square_move_left']: 'LEFT',
+ game.tui.keys['square_move_down']: 'DOWN',
+ game.tui.keys['square_move_right']: 'RIGHT',
}
elif type(game.map_geometry) == MapGeometryHex:
game.tui.movement_keys = {
- 'w': 'UPLEFT',
- 'e': 'UPRIGHT',
- 'd': 'RIGHT',
- 'c': 'DOWNRIGHT',
- 'x': 'DOWNLEFT',
- 's': 'LEFT',
+ game.tui.keys['hex_move_upleft']: 'UPLEFT',
+ game.tui.keys['hex_move_upright']: 'UPRIGHT',
+ game.tui.keys['hex_move_right']: 'RIGHT',
+ game.tui.keys['hex_move_downright']: 'DOWNRIGHT',
+ game.tui.keys['hex_move_downleft']: 'DOWNLEFT',
+ game.tui.keys['hex_move_left']: 'LEFT',
}
cmd_MAP.argtypes = 'string:map_geometry yx_tuple:pos string'
game.tui.query_info()
player = game.get_thing(game.player_id, False)
if player.position in game.portals:
- #host, port = game.portals[player.position].split(':')
game.tui.teleport_target_host = game.portals[player.position]
- game.tui.teleport_target_port = 5000
game.tui.switch_mode('teleport')
game.turn_complete = True
game.tui.do_refresh = True
self.shows_info = shows_info
self.is_intro = is_intro
- def __init__(self, host, port):
+ def __init__(self, host):
+ import os
+ import json
self.host = host
- self.port = port
self.mode_play = self.Mode('play')
self.mode_study = self.Mode('study', shows_info=True)
self.mode_edit = self.Mode('edit')
self.queue = queue.Queue()
self.login_name = None
self.switch_mode('waiting_for_server')
+ self.keys = {
+ 'switch_to_chat': 't',
+ 'switch_to_play': 'p',
+ 'switch_to_annotate': 'm',
+ 'switch_to_portal': 'P',
+ 'switch_to_study': '?',
+ 'switch_to_edit': 'm',
+ 'flatten': 'F',
+ 'hex_move_upleft': 'w',
+ 'hex_move_upright': 'e',
+ 'hex_move_right': 'd',
+ 'hex_move_downright': 'x',
+ 'hex_move_downleft': 'y',
+ 'hex_move_left': 'a',
+ 'square_move_up': 'w',
+ 'square_move_left': 'a',
+ 'square_move_down': 's',
+ 'square_move_right': 'd',
+ }
+ if os.path.isfile('config.json'):
+ with open('config.json', 'r') as f:
+ keys_conf = json.loads(f.read())
+ for k in keys_conf:
+ self.keys[k] = keys_conf[k]
curses.wrapper(self.loop)
def flash(self):
def send(self, msg):
try:
+ if hasattr(self.socket, 'plom_closed') and self.socket.plom_closed:
+ raise BrokenSocketConnection
self.socket.send(msg)
- except BrokenPipeError:
+ except (BrokenPipeError, BrokenSocketConnection):
self.log_msg('@ server disconnected :(')
self.do_refresh = True
else:
self.log_msg('@ enter username')
elif self.mode.name == 'teleport':
- self.log_msg("@ May teleport to %s:%s" % (self.teleport_target_host,
- self.teleport_target_port));
+ self.log_msg("@ May teleport to %s" % (self.teleport_target_host)),
self.log_msg("@ Enter 'YES!' to enthusiastically affirm.");
elif self.mode.name == 'annotate' and self.explorer in self.game.info_db:
info = self.game.info_db[self.explorer]
self.log_msg(" /nick NAME - re-name yourself to NAME");
self.log_msg(" /msg USER TEXT - send TEXT to USER");
self.log_msg(" /help - show this help");
- self.log_msg(" /P or /play - switch to play mode");
- self.log_msg(" /? or /study - switch to study mode");
+ self.log_msg(" /%s or /play - switch to play mode" % self.keys['switch_to_play']);
+ self.log_msg(" /%s or /study - switch to study mode" % self.keys['switch_to_study']);
self.log_msg("commands common to study and play mode:");
- if type(self.game.map_geometry) == MapGeometrySquare:
- self.log_msg(" w,a,s,d - move");
- elif type(self.game.map_geometry) == MapGeometryHex:
- self.log_msg(" e,d,c,x,s,w - move");
- self.log_msg(" C - switch to chat mode");
+ self.log_msg(" %s - move" % ','.join(self.movement_keys));
+ self.log_msg(" %s - switch to chat mode" % self.keys['switch_to_chat']);
self.log_msg("commands specific to play mode:");
- self.log_msg(" E - write following ASCII character");
- self.log_msg(" f - flatten surroundings");
- self.log_msg(" ? - switch to study mode");
+ self.log_msg(" %s - write following ASCII character" % self.keys['switch_to_edit']);
+ self.log_msg(" %s - flatten surroundings" % self.keys['flatten']);
+ self.log_msg(" %s - switch to study mode" % self.keys['switch_to_study']);
self.log_msg("commands specific to study mode:");
- self.log_msg(" E - annotate terrain");
- self.log_msg(" P - switch to play mode");
+ self.log_msg(" %s - annotate terrain" % self.keys['switch_to_annotate']);
+ self.log_msg(" %s - switch to play mode" % self.keys['switch_to_play']);
def loop(self, stdscr):
+ import time
def safe_addstr(y, x, line):
if y < self.size.y - 1 or x + len(line) < self.size.x:
stdscr.addstr(y, x, cut)
def connect():
- import time
- def recv_loop():
- for msg in self.socket.recv():
- if msg == 'BYE':
- break
+ def handle_recv(msg):
+ if msg == 'BYE':
+ self.socket.close()
+ else:
self.queue.put(msg)
+ socket_client_class = PlomSocketClient
+ if self.host.startswith('ws://') or self.host.startswith('wss://'):
+ socket_client_class = WebSocketClient
while True:
try:
- s = socket.create_connection((self.host, self.port))
- self.socket = PlomSocket(s)
- self.socket_thread = threading.Thread(target=recv_loop)
+ self.socket = socket_client_class(handle_recv, self.host)
+ self.socket_thread = threading.Thread(target=self.socket.run)
self.socket_thread.start()
self.switch_mode('login')
return
def reconnect():
self.send('QUIT')
+ time.sleep(0.1) # FIXME necessitated by some some strange SSL race
+ # conditions with ws4py, find out what exactly
self.switch_mode('waiting_for_server')
connect()
elif self.mode == self.mode_teleport and key == '\n':
if self.input_ == 'YES!':
self.host = self.teleport_target_host
- self.port = self.teleport_target_port
reconnect()
else:
self.log_msg('@ teleport aborted')
self.switch_mode('play')
self.input_ = ''
elif self.mode == self.mode_study:
- if key == 'C':
+ if key == self.keys['switch_to_chat']:
self.switch_mode('chat')
- elif key == 'P':
+ elif key == self.keys['switch_to_play']:
self.switch_mode('play')
- elif key == 'A':
+ elif key == self.keys['switch_to_annotate']:
self.switch_mode('annotate', keep_position=True)
- elif key == 'p':
+ elif key == self.keys['switch_to_portal']:
self.switch_mode('portal', keep_position=True)
elif key in self.movement_keys:
move_explorer(self.movement_keys[key])
elif self.mode == self.mode_play:
- if key == 'C':
+ if key == self.keys['switch_to_chat']:
self.switch_mode('chat')
- elif key == '?':
+ elif key == self.keys['switch_to_study']:
self.switch_mode('study')
- if key == 'E':
+ if key == self.keys['switch_to_edit']:
self.switch_mode('edit')
- elif key == 'f':
+ elif key == self.keys['flatten']:
self.send('TASK:FLATTEN_SURROUNDINGS')
elif key in self.movement_keys:
self.send('TASK:MOVE ' + self.movement_keys[key])
self.send('TASK:WRITE ' + key)
self.switch_mode('play')
-TUI('127.0.0.1', 5000)
+TUI('127.0.0.1:5000')