Skip to content

Commit b217bdc

Browse files
author
mudox
committed
Initial commit
0 parents  commit b217bdc

File tree

7 files changed

+519
-0
lines changed

7 files changed

+519
-0
lines changed

.gitignore

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
2+
# Created by https://www.gitignore.io/api/python
3+
4+
### Python ###
5+
# Byte-compiled / optimized / DLL files
6+
__pycache__/
7+
*.py[cod]
8+
*$py.class
9+
10+
# C extensions
11+
*.so
12+
13+
# Distribution / packaging
14+
.Python
15+
build/
16+
develop-eggs/
17+
dist/
18+
downloads/
19+
eggs/
20+
.eggs/
21+
lib/
22+
lib64/
23+
parts/
24+
sdist/
25+
var/
26+
wheels/
27+
*.egg-info/
28+
.installed.cfg
29+
*.egg
30+
31+
# PyInstaller
32+
# Usually these files are written by a python script from a template
33+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
34+
*.manifest
35+
*.spec
36+
37+
# Installer logs
38+
pip-log.txt
39+
pip-delete-this-directory.txt
40+
41+
# Unit test / coverage reports
42+
htmlcov/
43+
.tox/
44+
.coverage
45+
.coverage.*
46+
.cache
47+
nosetests.xml
48+
coverage.xml
49+
*.cover
50+
.hypothesis/
51+
52+
# Translations
53+
*.mo
54+
*.pot
55+
56+
# Django stuff:
57+
*.log
58+
local_settings.py
59+
60+
# Flask stuff:
61+
instance/
62+
.webassets-cache
63+
64+
# Scrapy stuff:
65+
.scrapy
66+
67+
# Sphinx documentation
68+
docs/_build/
69+
70+
# PyBuilder
71+
target/
72+
73+
# Jupyter Notebook
74+
.ipynb_checkpoints
75+
76+
# pyenv
77+
.python-version
78+
79+
# celery beat schedule file
80+
celerybeat-schedule
81+
82+
# SageMath parsed files
83+
*.sage.py
84+
85+
# Environments
86+
.env
87+
.venv
88+
env/
89+
venv/
90+
ENV/
91+
env.bak/
92+
venv.bak/
93+
94+
# Spyder project settings
95+
.spyderproject
96+
.spyproject
97+
98+
# Rope project settings
99+
.ropeproject
100+
101+
# mkdocs documentation
102+
/site
103+
104+
# mypy
105+
.mypy_cache/
106+
107+
# End of https://www.gitignore.io/api/python

JacServer.tmux-session.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env bash
2+
# vim: fdm=marker
3+
4+
CLIENT_WIDTH=213
5+
CLIENT_HEIGHT=57
6+
7+
session_name='JacKit'
8+
if tmux has-session -t ${session_name} &>/dev/null; then
9+
echo "session [${session_name}] already exisits, kill it!"
10+
tmux kill-session -t "${session_name}"
11+
fi
12+
13+
14+
#
15+
# Editor
16+
#
17+
18+
root="${HOME}/Develop/Python/jack-server/"
19+
window_name='Editor'
20+
window="${session_name}:${window_name}"
21+
tmux new-session \
22+
-s "${session_name}" \
23+
-n "${window_name}" \
24+
-x "$CLIENT_WIDTH" \
25+
-y "$CLIENT_HEIGHT" \
26+
-c "${root}" \
27+
-d
28+
29+
#
30+
# Log
31+
#
32+
33+
root="${HOME}/Git/vim-config"
34+
window_name='Log'
35+
window="${session_name}:${window_name}"
36+
tmux new-window -a -d \
37+
-t "${session_name}:{end}" \
38+
-n "${window_name}" \
39+
-c "${root}"
40+
sleep 1
41+
tmux send-keys -t "${window}" "
42+
vv vimrc
43+
"
44+
45+
tmux select-window -t "${session_name}:Editor"

demo.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
2+
from SocketServer import ThreadingMixIn
3+
import threading
4+
import argparse
5+
import re
6+
import cgi
7+
8+
9+
class LocalData(object):
10+
records = {}
11+
12+
13+
class HTTPRequestHandler(BaseHTTPRequestHandler):
14+
15+
# POST /log/
16+
#
17+
# Log event in JSON format
18+
def do_POST(self) >
19+
if re.search('/log/', self.path) is not None:
20+
length = int(self.headers.getheader('content-length'))
21+
data = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1)
22+
recordID = self.path.split('/')[-1]
23+
LocalData.records[recordID] = data
24+
25+
else:
26+
self.send_response(403)
27+
self.end_headers()
28+
29+
30+
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
31+
allow_reuse_address = True
32+
33+
def shutdown(self):
34+
self.socket.close()
35+
HTTPServer.shutdown(self)
36+
37+
38+
class SimpleHttpServer():
39+
40+
def __init__(self, ip, port):
41+
self.server = ThreadedHTTPServer((ip, port), HTTPRequestHandler)
42+
43+
def start(self):
44+
self.server_thread = threading.Thread(target=self.server.serve_forever)
45+
self.server_thread.daemon = True
46+
self.server_thread.start()
47+
48+
def waitForThread(self):
49+
self.server_thread.join()
50+
51+
def addRecord(self, recordID, jsonEncodedRecord):
52+
LocalData.records[recordID] = jsonEncodedRecord
53+
54+
def stop(self):
55+
self.server.shutdown()
56+
self.waitForThread()
57+
58+
59+
if __name__ == '__main__':
60+
parser = argparse.ArgumentParser(description='HTTP Server')
61+
parser.add_argument(
62+
'port',
63+
type=int,
64+
help='Listening port for HTTP Server')
65+
parser.add_argument('ip', help='HTTP Server IP')
66+
args = parser.parse_args()
67+
68+
server = SimpleHttpServer(args.ip, args.port)
69+
server.start()
70+
server.waitForThread()

event.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
from pathlib import Path
5+
from textwrap import indent
6+
7+
from shared import Settings
8+
from shared import colorize
9+
10+
LOG_ROOT = Path('~/Library/Logs/JacKit/').expanduser()
11+
LOG_ROOT.mkdir(exist_ok=True)
12+
13+
14+
class Event:
15+
16+
# Hold all opened file object for each senssionID
17+
# Created on each `POST /session/`
18+
# Where
19+
# - key: session ID
20+
# - value: opened file object
21+
jsonFiles = {}
22+
logFiles = {}
23+
24+
def __init__(self, jsonDict):
25+
self.jsonDict = jsonDict
26+
27+
def sessionID(self):
28+
return self.jsonDict['sessionID']
29+
30+
def timestamp(self):
31+
return self.jsonDict['timestamp']
32+
33+
def subsystem(self):
34+
return self.jsonDict['subsystem']
35+
36+
def level(self):
37+
return self.jsonDict['level']
38+
39+
def message(self):
40+
return self.jsonDict['message']
41+
42+
def logLine(self):
43+
symbol = Settings.symbols[self.level()]
44+
color1, color2 = Settings.colors[self.level()]
45+
46+
tagLine = colorize(f' {symbol}{self.subsystem()}', color1)
47+
messageLines = indent(self.message(), ' ')
48+
messageLines = colorize(messageLines, color2)
49+
return '\n'.join([tagLine, messageLines])

jacserver.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
5+
import datetime
6+
import json
7+
import socket
8+
import time
9+
from http.server import BaseHTTPRequestHandler, HTTPServer
10+
from os import system
11+
12+
from event import Event
13+
from shared import Settings, colorize
14+
15+
PORT = 7086
16+
17+
18+
def start():
19+
"""Start the server
20+
"""
21+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
22+
s.connect(("8.8.8.8", 80))
23+
ip = s.getsockname()[0]
24+
25+
httpd = HTTPServer((ip, 7086), HTTPRequestHandler)
26+
print('Start server listening at {}:7086 ...\n\n'.format(ip))
27+
httpd.serve_forever()
28+
29+
30+
class HTTPRequestHandler(BaseHTTPRequestHandler):
31+
"""Handle the request sent to server"""
32+
33+
server_version = 'JackServer/0.1'
34+
protocol_version = 'HTTP/1.1' # enable persistent connection
35+
36+
time_interval = 3
37+
last_timestamp = time.time()
38+
39+
def do_POST(self):
40+
if self.path == '/session/':
41+
self.newSession()
42+
elif self.path == '/event/':
43+
self.newEvent()
44+
else:
45+
self.send_error(
46+
403,
47+
'Invalid API path',
48+
'''
49+
Currently JackServeronly support:
50+
51+
- POST /session/ HTTP/1.1
52+
Notify of a new Xcode project running session
53+
54+
- POST /event/ HTTP/1.1
55+
Send a new event
56+
'''
57+
)
58+
return
59+
60+
def newSession(self):
61+
self.send_response(200)
62+
self.send_header('Content-Length', 0)
63+
self.end_headers()
64+
65+
system('clear')
66+
67+
def newEvent(self):
68+
self.send_response(200)
69+
self.send_header('Content-Length', 0)
70+
self.end_headers()
71+
72+
size = int(self.headers['Content-Length'])
73+
jsonDict = json.loads(self.rfile.read(size))
74+
self.event = Event(jsonDict)
75+
76+
self.printTimeSeparatorIfNeeded()
77+
print(self.event.logLine())
78+
79+
def printTimeSeparatorIfNeeded(self):
80+
seconds = self.event.timestamp() - HTTPRequestHandler.last_timestamp
81+
82+
if seconds > HTTPRequestHandler.time_interval:
83+
color1, color2 = Settings.colors['time_sep']
84+
85+
delta = datetime.timedelta(seconds=seconds)
86+
prefix = colorize('\n -- ', color2)
87+
deltaColored = colorize(delta, color1)
88+
suffix = colorize(' elapsed ---\n', color2)
89+
timeLine = f'{prefix}{deltaColored}{suffix}'
90+
91+
print(timeLine)
92+
93+
HTTPRequestHandler.last_timestamp = self.event.timestamp()
94+
95+
96+
try:
97+
system('stty -echo; clear; tput civis')
98+
start()
99+
except KeyboardInterrupt:
100+
exit(0)
101+
except Exception as e:
102+
exit(1)
103+
else:
104+
exit(0)
105+
finally:
106+
system('tput cnorm; stty echo')

0 commit comments

Comments
 (0)