浏览代码

make client interactive

Eren Yilmaz 6 年之前
父节点
当前提交
baa36e0ac4
共有 6 个文件被更改,包括 182 次插入29 次删除
  1. 72 9
      client.py
  2. 71 0
      client_controller.py
  3. 19 0
      connection.py
  4. 6 5
      server.py
  5. 13 15
      server_controller.py
  6. 1 0
      util.py

+ 72 - 9
client.py

@@ -1,12 +1,75 @@
-import json
-import requests
-import connection
+import sys
+import time
 
-host = 'http://127.0.0.1:' + str(connection.port)
+import client_controller
 
-headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
-r = requests.post(host + '/register', data=json.dumps({"username": "user1", "password": "qwertz"}), headers=headers)
-print(r.content)
+from util import debug
 
-r = requests.post(host + '/login', data=json.dumps({"username": "user1", "password": "qwertz"}), headers=headers)
-print(r.content)
+
+def fake_loading_bar(msg,delay=0.100):
+    if len(msg) >= 32:
+        raise AssertionError('Loading bar label too larger')
+    msg += ':'
+    msg += ' ' * (32 - len(msg))
+    print(msg, end='')
+    sys.stdout.flush()
+    for _ in range(50):
+        if not debug:
+            time.sleep(delay)
+        print('#', end='')
+        sys.stdout.flush()
+    print('\n', end='')
+    sys.stdout.flush()
+
+
+def load():
+    print('Loading...')
+
+    fake_loading_bar('Initializing fake loading bars')
+    fake_loading_bar('Loading data from disk')
+    fake_loading_bar('Loading available commands')
+    fake_loading_bar('Updating indices')
+    fake_loading_bar('Waiting')
+    print('Done.\n\n')
+
+
+def welcome():
+    print('''
+    $$$$$$\                  $$\                                         
+    $$  __$$\                 $$ |                                        
+    $$ /  $$ | $$$$$$\   $$$$$$$ | $$$$$$\   $$$$$$\   $$$$$$\   $$$$$$\  
+    $$ |  $$ |$$  __$$\ $$  __$$ |$$  __$$\ $$  __$$\ $$  __$$\ $$  __$$\ 
+    $$ |  $$ |$$ |  \__|$$ /  $$ |$$$$$$$$ |$$ |  \__|$$$$$$$$ |$$ |  \__|
+    $$ |  $$ |$$ |      $$ |  $$ |$$   ____|$$ |      $$   ____|$$ |      
+     $$$$$$  |$$ |      \$$$$$$$ |\$$$$$$$\ $$ |      \$$$$$$$\ $$ |      
+     \______/ \__|       \_______| \_______|\__|       \_______|\__|      
+                                                                      
+                                                                      
+                                                                      
+To display an overview of available commands type \'help\'.
+
+''')
+
+
+def one_command():
+    cmd = input('*> ')
+    cmds = cmd.split(';')
+    for cmd in cmds:
+        cmd = cmd.split(' ')
+        if cmd[0] not in allowed_commands:
+            print('Invalid command.')
+        else:
+            method_to_call = getattr(client_controller, cmd[0])
+            try:
+                method_to_call(*cmd[1:])
+            except TypeError:
+                print('Invalid command syntax.')
+
+
+if __name__ == '__main__':
+    load()
+    welcome()
+
+    while True:
+        one_command()
+allowed_commands = ['login', 'register', 'help']

+ 71 - 0
client_controller.py

@@ -0,0 +1,71 @@
+import getpass
+import inspect
+import sys
+import client
+import connection
+from client import allowed_commands
+from connection import client_request
+
+
+def login(username=None, password=None):
+    if connection.session_id is not None:
+        client.fake_loading_bar('Signing out', delay=0.025)
+        connection.session_id = None
+
+    if username is None:
+        username = input('Username: ')
+
+    if password is None:
+        if sys.stdin.isatty():
+            password = getpass.getpass('Password: ')
+        else:
+            password = input('Password: ')
+
+    response = client_request('login', {"username": username, "password": password})
+    success = 'session_id' in response
+    if success:
+        connection.session_id = response['session_id']
+        print('Login successful.')
+    else:
+        if 'error_message' in response:
+            print('Login failed with message:', response['error_message'])
+        else:
+            print('Login failed.')
+
+
+def register(username, password=None):
+    if connection.session_id is not None:
+        client.fake_loading_bar('Signing out', delay=0.025)
+        connection.session_id = None
+
+    if username is None:
+        username = input('Username: ')
+
+    if password is None:
+        if sys.stdin.isatty():
+            password = getpass.getpass('Password: ')
+        else:
+            password = input('Password: ')
+
+    response = client_request('register', {"username": username, "password": password})
+    success = 'session_id' in response
+    if success:
+        connection.session_id = response['session_id']
+        print('Registration successful.')
+    else:
+        if 'error_message' in response:
+            print('Registration failed with message:', response['error_message'])
+        else:
+            print('Registration failed.')
+
+
+def help():
+    print('Allowed commands:')
+    for cmd in allowed_commands:
+        this_module = sys.modules[__name__]
+        method = getattr(this_module, cmd[0])
+        params = inspect.signature(method).parameters
+        num_args = len(params)
+        print(cmd, 'takes the following', num_args, 'arguments:')
+        for p in params:
+            print(' ', p) # TODO print default value

+ 19 - 0
connection.py

@@ -1 +1,20 @@
+import json
+
+import requests
+
+from util import debug
+
 port = 8451
+host = 'http://127.0.0.1:' + str(port)
+json_headers = {'Content-type': 'application/json'}
+
+
+def client_request(route, data):
+    r = requests.post(host + '/' + route, data=json.dumps(data),
+                         headers=json_headers)
+    if debug:
+        print('Request returned: ' + str(r.content))
+    return r.json()
+
+
+session_id = None

+ 6 - 5
server.py

@@ -1,11 +1,12 @@
 import sqlite3
 
 import connection
-import controller
+import server_controller
 import model
 from bottle import run, request, response, route
 
-from controller import not_found
+from server_controller import not_found
+from util import debug
 
 if __name__ == '__main__':
     print('sqlite3.version', model.db.version)
@@ -20,10 +21,10 @@ if __name__ == '__main__':
         if path not in valid_routes:
             return not_found()
         response.content_type = 'application/json'
-        method_to_call = getattr(controller, path)
+        method_to_call = getattr(server_controller, path)
         try:
             return method_to_call()
         except sqlite3.IntegrityError:
-            return controller.bad_request('action violates database constraints')
+            return server_controller.bad_request('action violates database constraints')
 
-    run(host='localhost', port=connection.port, debug=True)
+    run(host='localhost', port=connection.port, debug=debug)

+ 13 - 15
controller.py → server_controller.py

@@ -3,6 +3,7 @@ import json
 from bottle import request, response
 
 import model
+from util import debug
 
 
 def missing_attributes(attributes):
@@ -40,28 +41,25 @@ def register():
         bad_request('registration not successful')
 
 
-def not_found(msg=None):
+def not_found(msg=''):
     response.status = 404
+    if debug:
+        msg = str(response.status) + ' Page not found: ' + msg
     response.content_type = 'application/json'
-    if msg is None:
-        return json.dumps({"error": "404: Page not found"})
-    else:
-        return json.dumps({"error": "404: Page not found: " + msg})
+    return json.dumps({"error_message": msg})
 
 
-def forbidden(msg=None):
+def forbidden(msg=''):
     response.status = 403
+    if debug:
+        msg = str(response.status) + ' Forbidden: ' + msg
     response.content_type = 'application/json'
-    if msg is None:
-        return json.dumps({"error": "403: Forbidden"})
-    else:
-        return json.dumps({"error": "403: Forbidden: " + msg})
+    return json.dumps({"error_message": msg})
 
 
-def bad_request(msg=None):
+def bad_request(msg=''):
     response.status = 400
+    if debug:
+        msg = str(response.status) + ' Bad request: ' + msg
     response.content_type = 'application/json'
-    if msg is None:
-        return json.dumps({"error": "400: Bad request"})
-    else:
-        return json.dumps({"error": "400: Bad request: " + msg})
+    return json.dumps({"error_message": msg})

+ 1 - 0
util.py

@@ -0,0 +1 @@
+debug = True