pull/4/head
commit
d23c98e5e7
|
@ -0,0 +1,162 @@
|
||||||
|
Text Entities
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The `entities` attribute is an array of objects that represent blocks
|
||||||
|
of text within a post that have special properties. Clients may safely
|
||||||
|
ignore these things without losing too much meaning, but in a rich
|
||||||
|
application like an Emacs or GUI implementation, they can provide
|
||||||
|
some highlighting and navigation perks. The array object may be
|
||||||
|
empty. If its not, its populated with arrays representing the
|
||||||
|
modifications to be made.
|
||||||
|
|
||||||
|
Objects **always** have a minimum of 3 attributes:
|
||||||
|
```
|
||||||
|
["quote", 5, 7]
|
||||||
|
```
|
||||||
|
object[0] is a string representing the attribute type. They are
|
||||||
|
documented below. The next two items are the indices of the
|
||||||
|
property in the body string. The way clients are to access these
|
||||||
|
indices is beyond the scope of this document; accessing a subsequence
|
||||||
|
varies a lot between programming languages.
|
||||||
|
|
||||||
|
Some objects will provide further arguments beyond those 3.
|
||||||
|
|
||||||
|
|--------------|----------------------------------------------------------|
|
||||||
|
| Name | Description |
|
||||||
|
|--------------|----------------------------------------------------------|
|
||||||
|
| `quote` | This is a string that refers to a previous post number. |
|
||||||
|
| | These are formatted like >>5, which means it is a |
|
||||||
|
| | reference to `post_id` 5. These are not processed in |
|
||||||
|
| | thread OPs. >>0 may be used to refer to the OP. |
|
||||||
|
|--------------|----------------------------------------------------------|
|
||||||
|
| `blockquote` | This is a block of text, denoted by a newline during |
|
||||||
|
| | composure, representing text that is assumed to be |
|
||||||
|
| | a quote of someone else. |
|
||||||
|
|--------------|----------------------------------------------------------|
|
||||||
|
| `color` | This is a block of text, denoted by [[color: body]] |
|
||||||
|
| | during composure. The body may span across newlines. |
|
||||||
|
| | A fourth item is provided in the array: it is one of the |
|
||||||
|
| | following strings representing the color. |
|
||||||
|
| | `red`, `green`, `yellow`, `blue`, `magenta`, or `cyan`. |
|
||||||
|
|--------------|----------------------------------------------------------|
|
||||||
|
| `bold` | Like color, except that no additional attribute is |
|
||||||
|
| | provided. it is denoted as [[bold: body]] during |
|
||||||
|
| | composure. |
|
||||||
|
|--------------|----------------------------------------------------------|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Threads & Replies
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Threads are represented the same when using `thread_index` and
|
||||||
|
`thread_load`, except that the `replies` attribute is only
|
||||||
|
present with `thread_load`. The following attributes are
|
||||||
|
available on the parent object:
|
||||||
|
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| Name | Description |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `author` | The ID of the author |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `thread_id` | The ID of the thread. |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `title` | The title string of the thread |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `body` | The body of the post's text. |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `entities` | A (possibly empty) array of entity objects for |
|
||||||
|
| | the post `body`. |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `tags` | An array of strings representing tags the |
|
||||||
|
| | author gave to the thread at creation. |
|
||||||
|
| | When empty, it is an array with no elements. |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `replies` | An array containing full reply objects in |
|
||||||
|
| | the order they were posted. Your clients |
|
||||||
|
| | do not need to sort these. |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `reply_count` | An integer representing the number of replies |
|
||||||
|
| | that have been posted in this thread. |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `lastmod` | Unix timestamp of when the thread was last |
|
||||||
|
| | posted in, or a message was edited. |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `edited` | Boolean of whether this post has been edited since |
|
||||||
|
| | it was made. |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
| `created` | Unix timestamp of when the post was originally made. |
|
||||||
|
|---------------|------------------------------------------------------|
|
||||||
|
|
||||||
|
The following attributes are available on each reply object in `replies`:
|
||||||
|
|
||||||
|
|
||||||
|
|------------|---------------------------------------------------------|
|
||||||
|
| Name | Description |
|
||||||
|
|------------|---------------------------------------------------------|
|
||||||
|
| `post_id` | An integer of the posts ID; unlike thread and user ids, |
|
||||||
|
| | this is not a uuid but instead is incremental, starting |
|
||||||
|
| | from 1 as the first reply and going up by one for each |
|
||||||
|
| | post. |
|
||||||
|
|------------|---------------------------------------------------------|
|
||||||
|
| `author` | Author ID |
|
||||||
|
|------------|---------------------------------------------------------|
|
||||||
|
| `body` | The body the reply's text. |
|
||||||
|
|------------|---------------------------------------------------------|
|
||||||
|
| `entities` | A (possibly empty) array of entity objects for |
|
||||||
|
| | the reply `body`. |
|
||||||
|
|------------|---------------------------------------------------------|
|
||||||
|
| `lastmod` | Unix timestamp of when the post was last edited, or |
|
||||||
|
| | the same as `created` if it never was. |
|
||||||
|
|------------|---------------------------------------------------------|
|
||||||
|
| `edited` | A boolean of whether the post was edited. |
|
||||||
|
|------------|---------------------------------------------------------|
|
||||||
|
| `created` | Unix timestamp of when the reply was originally posted. |
|
||||||
|
|------------|---------------------------------------------------------|
|
||||||
|
|
||||||
|
|
||||||
|
Errors
|
||||||
|
------
|
||||||
|
|
||||||
|
Errors are represented in the `error` field of the response. The error
|
||||||
|
field is always present, but is usually false. If its not false, it is
|
||||||
|
an object with the fields `code` and `description`. `code` is an integer
|
||||||
|
representing the type of failure, and `description` is a string describing
|
||||||
|
the problem. `description` is intended for human consumption; in your client
|
||||||
|
code, use the error codes to handle conditions. The `presentable` column
|
||||||
|
indicates whether the `description` should be shown to users verbatim.
|
||||||
|
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| Code | Presentable | Documentation |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 0 | Never, fix | Malformed json input. `description` is the error |
|
||||||
|
| | your client | string thrown by the server-side json decoder. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 1 | Not a good | Internal server error. Unaltered exception text |
|
||||||
|
| | idea, the | is returned as `description`. This shouldn't |
|
||||||
|
| | exceptions | happen, and if it does, make a bug report. |
|
||||||
|
| | are not | clients should not attempt to intelligently |
|
||||||
|
| | helpful | recover from any errors of this class. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 2 | Nadda. | Unknown `method` was requested. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 3 | Fix. Your. | Missing or malformed parameter values for the |
|
||||||
|
| | Client. | requested `method`. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 4 | Only during | Invalid or unprovided `user`. During |
|
||||||
|
| | registration | registration, this code is returned if the name |
|
||||||
|
| | | is already occupied or contains illegal chars. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 5 | Always | `user` is not registered. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 6 | Always | User `auth_hash` failed or was not provided. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 7 | Always | Requested thread does not exist. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 8 | Always | Requested thread does not allow posts. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 9 | Always | Message edit failed; there is a 24hr limit for |
|
||||||
|
| | | editing posts. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
||||||
|
| 10 | Always | User action requires `admin` privilege. |
|
||||||
|
|------|--------------|--------------------------------------------------|
|
|
@ -0,0 +1,37 @@
|
||||||
|
(require 'json)
|
||||||
|
|
||||||
|
(defvar bbj:host "localhost")
|
||||||
|
(defvar bbj:port "7066")
|
||||||
|
(defvar bbj:logged-in nil)
|
||||||
|
(defvar bbj:user nil)
|
||||||
|
(defvar bbj:hash nil)
|
||||||
|
|
||||||
|
|
||||||
|
(defun bbj:request (&rest cells)
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert (json-encode cells))
|
||||||
|
(shell-command-on-region
|
||||||
|
(point-min) (point-max)
|
||||||
|
(format "nc %s %s" bbj:host bbj:port)))
|
||||||
|
(with-current-buffer "*Shell Command Output*"
|
||||||
|
(json-read-from-string
|
||||||
|
(buffer-substring-no-properties
|
||||||
|
(point-min) (point-max)))))
|
||||||
|
|
||||||
|
|
||||||
|
(bbj:request '(user . "desvox")
|
||||||
|
'(auth_hash . "nrr")
|
||||||
|
'(method . "check_auth"))
|
||||||
|
|
||||||
|
(defun bbj:login ()
|
||||||
|
(interactive)
|
||||||
|
(setq bbj:user (read-from-minibuffer "(BBJ Username)> "))
|
||||||
|
(if (bbj:request '(method . "is_registered")
|
||||||
|
`(target_user . ,bbj:user))
|
||||||
|
(setq bbj:hash (secure-hash 'sha256 (read-from-minibuffer "(BBJ Password)> ")))
|
||||||
|
(when (y-or-n-p (format "Register for BBJ as %s? " bbj:user))
|
||||||
|
(message
|
||||||
|
(bbj:request (cons 'auth_hash bbj:hash)
|
||||||
|
(cons 'user bbj:user)
|
||||||
|
(cons 'avatar nil)
|
||||||
|
(cons 'bio (read-from-minibuffer "(Enter a short bio about youself!)> ")))))))
|
|
@ -0,0 +1,4 @@
|
||||||
|
from src import schema
|
||||||
|
from src import server
|
||||||
|
|
||||||
|
server.run("localhost", 7066)
|
|
@ -0,0 +1,114 @@
|
||||||
|
from uuid import uuid1
|
||||||
|
from src import schema
|
||||||
|
from time import time
|
||||||
|
from os import path
|
||||||
|
import json
|
||||||
|
|
||||||
|
PATH = "/home/desvox/bbj/"
|
||||||
|
|
||||||
|
if not path.isdir(PATH):
|
||||||
|
path.os.mkdir(PATH, mode=0o744)
|
||||||
|
|
||||||
|
if not path.isdir(path.join(PATH, "threads")):
|
||||||
|
path.os.mkdir(path.join(PATH, "threads"), mode=0o744)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(path.join(PATH, "userdb"), "r") as f:
|
||||||
|
USERDB = json.loads(f.read())
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
USERDB = dict(mapname=dict())
|
||||||
|
with open(path.join(PATH, "userdb"), "w") as f:
|
||||||
|
f.write(json.dumps(USERDB))
|
||||||
|
path.os.chmod(path.join(PATH, "userdb"), 0o600)
|
||||||
|
|
||||||
|
### THREAD MANAGEMENT ###
|
||||||
|
|
||||||
|
def thread_index(key="lastmod"):
|
||||||
|
result = list()
|
||||||
|
for ID in path.os.listdir(path.join(PATH, "threads")):
|
||||||
|
thread = thread_load(ID)
|
||||||
|
thread.pop("replies")
|
||||||
|
result.append(thread)
|
||||||
|
return sorted(result, key=lambda i: i[key])
|
||||||
|
|
||||||
|
|
||||||
|
def thread_create(author, body, title, tags):
|
||||||
|
ID = uuid1().hex
|
||||||
|
# make sure None, False, and empty arrays are always repped consistently
|
||||||
|
tags = tags if tags else []
|
||||||
|
scheme = schema.thread(ID, author, body, title, tags)
|
||||||
|
thread_dump(ID, scheme)
|
||||||
|
return scheme
|
||||||
|
|
||||||
|
|
||||||
|
def thread_load(ID):
|
||||||
|
try:
|
||||||
|
with open(path.join(PATH, "threads", ID), "r") as f:
|
||||||
|
return json.loads(f.read())
|
||||||
|
except FileNotFoundError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def thread_dump(ID, obj):
|
||||||
|
with open(path.join(PATH, "threads", ID), "w") as f:
|
||||||
|
f.write(json.dumps(obj))
|
||||||
|
|
||||||
|
|
||||||
|
def thread_reply(ID, author, body):
|
||||||
|
thread = thread_load(ID)
|
||||||
|
if not thread:
|
||||||
|
return schema.error(7, "Requested thread does not exist.")
|
||||||
|
|
||||||
|
thread["reply_count"] += 1
|
||||||
|
thread["lastmod"] = time()
|
||||||
|
reply = schema.reply(thread["reply_count"], author, body)
|
||||||
|
thread["replies"].append(reply)
|
||||||
|
thread_dump(ID, thread)
|
||||||
|
return reply
|
||||||
|
|
||||||
|
|
||||||
|
### USER MANAGEMENT ###
|
||||||
|
|
||||||
|
def user_dbdump(dictionary):
|
||||||
|
with open(path.join(PATH, "userdb"), "w") as f:
|
||||||
|
f.write(json.dumps(dictionary))
|
||||||
|
|
||||||
|
|
||||||
|
def user_resolve(name_or_id):
|
||||||
|
check = USERDB.get(name_or_id)
|
||||||
|
try:
|
||||||
|
if check:
|
||||||
|
return name_or_id
|
||||||
|
else:
|
||||||
|
return USERDB["mapname"][name_or_id]
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def user_register(auth_hash, name, avatar, bio):
|
||||||
|
if USERDB["mapname"].get(name):
|
||||||
|
return schema.error(4, "Username taken.")
|
||||||
|
|
||||||
|
ID = uuid1().hex
|
||||||
|
scheme = schema.user_internal(ID, auth_hash, name, avatar, bio, False)
|
||||||
|
USERDB.update({ID: scheme})
|
||||||
|
USERDB["mapname"].update({name: ID})
|
||||||
|
user_dbdump(USERDB)
|
||||||
|
return scheme
|
||||||
|
|
||||||
|
|
||||||
|
def user_get(ID):
|
||||||
|
user = USERDB[ID]
|
||||||
|
return schema.user_external(
|
||||||
|
ID, user["name"], user["avatar"],
|
||||||
|
user["bio"], user["admin"])
|
||||||
|
|
||||||
|
|
||||||
|
def user_auth(ID, auth_hash):
|
||||||
|
return auth_hash == USERDB[ID]["auth_hash"]
|
||||||
|
|
||||||
|
|
||||||
|
def user_update(ID, **params):
|
||||||
|
USERDB[ID].update(params)
|
||||||
|
return USERDB[ID]
|
|
@ -0,0 +1,77 @@
|
||||||
|
from src import schema
|
||||||
|
from src import db
|
||||||
|
from json import dumps
|
||||||
|
|
||||||
|
endpoints = {
|
||||||
|
"check_auth": ["user", "auth_hash"],
|
||||||
|
"is_registered": ["target_user"],
|
||||||
|
"thread_load": ["thread_id"],
|
||||||
|
"thread_index": [],
|
||||||
|
"thread_create": ["title", "body", "tags"],
|
||||||
|
"thread_reply": ["thread_id", "body"],
|
||||||
|
"user_register": ["user", "auth_hash", "avatar", "bio"],
|
||||||
|
"user_get": ["target_user"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
authless = [
|
||||||
|
"is_registered",
|
||||||
|
"user_register"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def create_usermap(thread, index=False):
|
||||||
|
if index:
|
||||||
|
return {user: db.user_get(user) for user in
|
||||||
|
{i["author"] for i in thread}}
|
||||||
|
|
||||||
|
result = {reply["author"] for reply in thread["replies"]}
|
||||||
|
result.add(thread["author"])
|
||||||
|
return {x: db.user_get(x) for x in result}
|
||||||
|
|
||||||
|
|
||||||
|
def is_registered(json):
|
||||||
|
return dumps(bool(db.USERDB["mapname"].get(json["target_user"])))
|
||||||
|
|
||||||
|
|
||||||
|
def check_auth(json):
|
||||||
|
return dumps(bool(db.user_auth(json["user"], json["auth_hash"])))
|
||||||
|
|
||||||
|
|
||||||
|
def user_register(json):
|
||||||
|
return schema.response(
|
||||||
|
db.user_register(
|
||||||
|
json["auth_hash"],
|
||||||
|
json["user"],
|
||||||
|
json["avatar"],
|
||||||
|
json["bio"]))
|
||||||
|
|
||||||
|
|
||||||
|
def thread_index(json):
|
||||||
|
index = db.thread_index()
|
||||||
|
return schema.response(
|
||||||
|
{"threads": index}, create_usermap(index, True))
|
||||||
|
|
||||||
|
|
||||||
|
def thread_load(json):
|
||||||
|
thread = db.thread_load(json["thread_id"])
|
||||||
|
if not thread:
|
||||||
|
return schema.error(7, "Requested thread does not exist")
|
||||||
|
return schema.response(thread, create_usermap(thread))
|
||||||
|
|
||||||
|
|
||||||
|
def thread_create(json):
|
||||||
|
thread = db.thread_create(
|
||||||
|
json["user"],
|
||||||
|
json["body"],
|
||||||
|
json["title"],
|
||||||
|
json["tags"])
|
||||||
|
return schema.response(thread, create_usermap(thread))
|
||||||
|
|
||||||
|
|
||||||
|
def thread_reply(json):
|
||||||
|
thread = db.thread_reply(
|
||||||
|
json["thread_id"],
|
||||||
|
json["user"],
|
||||||
|
json["body"])
|
||||||
|
return schema.response(thread)
|
|
@ -0,0 +1,77 @@
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
def base():
|
||||||
|
return {
|
||||||
|
"usermap": {},
|
||||||
|
"error": False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def response(dictionary, usermap=None):
|
||||||
|
result = base()
|
||||||
|
result.update(dictionary)
|
||||||
|
if usermap:
|
||||||
|
result["usermap"] = usermap
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def error(code, description):
|
||||||
|
result = base()
|
||||||
|
result.update({
|
||||||
|
"error": {
|
||||||
|
"description": description,
|
||||||
|
"code": code
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def user_internal(ID, auth_hash, name, avatar, bio, admin):
|
||||||
|
return {
|
||||||
|
"user_id": ID,
|
||||||
|
"avatar": avatar,
|
||||||
|
"name": name,
|
||||||
|
"bio": bio,
|
||||||
|
"admin": admin,
|
||||||
|
"auth_hash": auth_hash
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def user_external(ID, name, avatar, bio, admin):
|
||||||
|
return {
|
||||||
|
"user_id": ID,
|
||||||
|
"avatar": avatar,
|
||||||
|
"name": name,
|
||||||
|
"bio": bio,
|
||||||
|
"admin": admin
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def thread(ID, author, body, title, tags):
|
||||||
|
now = time()
|
||||||
|
return {
|
||||||
|
"thread_id": ID,
|
||||||
|
"author": author,
|
||||||
|
"body": body,
|
||||||
|
"entities": list(),
|
||||||
|
"title": title,
|
||||||
|
"tags": tags,
|
||||||
|
"replies": list(),
|
||||||
|
"reply_count": 0,
|
||||||
|
"lastmod": now,
|
||||||
|
"edited": False,
|
||||||
|
"created": now
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def reply(ID, author, body):
|
||||||
|
now = time()
|
||||||
|
return {
|
||||||
|
"post_id": ID,
|
||||||
|
"author": author,
|
||||||
|
"body": body,
|
||||||
|
"entities": list(),
|
||||||
|
"lastmod": now,
|
||||||
|
"edited": False,
|
||||||
|
"created": now
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
from socketserver import StreamRequestHandler, TCPServer
|
||||||
|
from src import endpoints
|
||||||
|
from src import schema
|
||||||
|
from src import db
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class RequestHandler(StreamRequestHandler):
|
||||||
|
"""
|
||||||
|
Receieves and processes json input; dispatches input to the
|
||||||
|
approproate endpoint, or responds with error objects.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def reply(self, dictionary):
|
||||||
|
self.wfile.write(bytes(json.dumps(dictionary), "utf8"))
|
||||||
|
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
try:
|
||||||
|
request = json.loads(str(self.rfile.read(), "utf8"))
|
||||||
|
endpoint = request.get("method")
|
||||||
|
|
||||||
|
if endpoint not in endpoints.endpoints:
|
||||||
|
raise IndexError("Invalid endpoint")
|
||||||
|
|
||||||
|
# check to make sure all the arguments for endpoint are provided
|
||||||
|
elif any([key not in request for key in endpoints.endpoints[endpoint]]):
|
||||||
|
raise ValueError("{} requires: {}".format(
|
||||||
|
endpoint, ", ".join(endpoints.endpoints[endpoint])))
|
||||||
|
|
||||||
|
elif endpoint not in endpoints.authless:
|
||||||
|
if not request.get("user"):
|
||||||
|
raise ConnectionError("No username provided.")
|
||||||
|
|
||||||
|
user = db.user_resolve(request["user"])
|
||||||
|
request["user"] = user
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
raise ConnectionAbortedError("User not registered")
|
||||||
|
|
||||||
|
elif endpoint != "check_auth" and not db.user_auth(user, request.get("auth_hash")):
|
||||||
|
raise ConnectionRefusedError("Authorization failed.")
|
||||||
|
|
||||||
|
except json.decoder.JSONDecodeError as E:
|
||||||
|
return self.reply(schema.error(0, str(E)))
|
||||||
|
|
||||||
|
except IndexError as E:
|
||||||
|
return self.reply(schema.error(2, str(E)))
|
||||||
|
|
||||||
|
except ValueError as E:
|
||||||
|
return self.reply(schema.error(3, str(E)))
|
||||||
|
|
||||||
|
except ConnectionError as E:
|
||||||
|
return self.reply(schema.error(4, str(E)))
|
||||||
|
|
||||||
|
except ConnectionAbortedError as E:
|
||||||
|
return self.reply(schema.error(5, str(E)))
|
||||||
|
|
||||||
|
except ConnectionRefusedError as E:
|
||||||
|
return self.reply(schema.error(6, str(E)))
|
||||||
|
|
||||||
|
except Exception as E:
|
||||||
|
return self.reply(schema.error(1, str(E)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.reply(eval("endpoints." + endpoint)(request))
|
||||||
|
except Exception as E:
|
||||||
|
self.reply(schema.error(1, str(E)))
|
||||||
|
|
||||||
|
|
||||||
|
def run(host, port):
|
||||||
|
server = TCPServer((host, port), RequestHandler)
|
||||||
|
try:
|
||||||
|
server.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("bye")
|
||||||
|
server.server_close()
|
Loading…
Reference in New Issue