목차
728x90
반응형
SMALL
// http_server/dir/statics/myscript.js
const myInterval = setInterval(myTimer, 1000);
function myTimer() {
const date = new Date();
document.getElementById('timer').innerHTML = '현재 시간: ' + date.toLocaleTimeString() + '<br><button onclick="myTimerStop()">Stop time</button><br>';
}
function myTimerStop() {
clearInterval(myInterval);
}
<!-- http_server/dir/index.html -->
<!DOCTYPE html>
<html>
<body>
<h1>index.html</h1>
<p>총 방문자: {{ COUNTER }}</p>
<div id="timer">
</div>
</body>
<script src="statics/myscript.js"></script>
</html>
# http_server/http_server.py
import os
import http
import http.server
import socketserver
import sqlite3
PREFIX = '/counter'
FLAGS = _ = None
DEBUG = False
EXT = {'.html': 'text/html;charset=utf-8',
'.js': 'text/javascript;charset=utf-8'}
CONN = sqlite3.connect('./Log.db')
CUR = CONN.cursor()
CUR.execute('''CREATE TABLE IF NOT EXISTS Log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT,
request TEXT);''')
CONN.commit()
class MyHTTPDaemon(http.server.HTTPServer):
allow_reuse_address = True
class MyHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
self.rootdir = FLAGS.rootdir
self.conn = CONN
self.cur = CUR
super().__init__(*args, **kwargs)
def do_GET(self):
if DEBUG:
print(f'Command: {self.command}')
print(f'Path: {self.path}')
print(f'Headers: {self.headers}')
self.cur.execute('''INSERT INTO Log (ip, request)
VALUES (?, ?);''', (self.client_address[0], self.requestline))
self.conn.commit()
if not self.path.startswith(PREFIX):
return None
self.path = self.path[len(PREFIX):]
if self.path == '/':
path = 'index.html'
else:
path = self.path[1:]
path = os.path.join(self.rootdir, path)
if DEBUG:
print(f'Joined path: {self.rootdir} {self.path} {path}')
if not os.path.exists(path):
self.send_error(http.HTTPStatus.NOT_FOUND, 'File not found')
else:
ext = os.path.splitext(path)[-1].lower()
self.send_response(http.HTTPStatus.OK)
self.send_header('Content-Type', EXT[ext])
with open(path, 'rb') as f:
self.cur.execute('''SELECT MAX(id) FROM Log;''')
counter = self.cur.fetchone()[0]
body = f.read()
body = body.replace('{{ COUNTER }}'.encode('utf-8'), f'{counter}'.encode('utf-8'))
self.send_header('Content-Length', len(body))
self.end_headers()
self.wfile.write(body)
def main():
print(f'Parsed arguments: {FLAGS}')
print(f'Unparsed arguments: {_}')
with MyHTTPDaemon((FLAGS.host, FLAGS.port),
MyHTTPRequestHandler) as httpd:
try:
print(f'Start server {httpd.server_address}')
httpd.serve_forever()
except KeyboardInterrupt:
print(f'Stop server {httpd.server_address}')
httpd.shutdown()
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--debug', action='store_true',
help='Debug message')
parser.add_argument('--host', default='0.0.0.0', type=str,
help='IP address')
parser.add_argument('--port', default=8888, type=int,
help='Port number')
parser.add_argument('--rootdir', default='./dir', type=str,
help='Root directory')
FLAGS, _ = parser.parse_known_args()
DEBUG = FLAGS.debug
main()
만약 http_server.py에 PREFIX를 추가하지 않으면,
-- 실습 --
<!-- mybp/templates/index.html -->
<!DOCTYPE html>
<html>
<title>My Paste Bin - Main</title>
<link rel="stylesheet" href="{{ url_for('mybp.static', filename='maincss.css') }}">
<body>
<h1>Pastes ( {{ count_pastes }} pastes from {{ count_users }} users )</h1>
<div id='pastes'>
</div>
</body>
<script src="{{ url_for('mybp.static', filename='mainjs.js') }}"></script>
</html>
// mybp/static/mainjs.js
async function fetchRequestWithError() {
try {
const url = `http://localhost:8080/pastebin/api/pastes/`;
const response = await fetch(url);
if (response.status >= 200 && response.status < 400) {
const data = await response.json();
for (var key in data) {
ndiv = document.createElement('div');
ndiv.innerHTML = `<h3> ${data[key]['title']} </h3><p> ${data[key]['content']}</p><hr>`;
pdiv = document.getElementById('pastes');
pdiv.appendChild(ndiv);
}
} else {
console.log(`${response.statusText}: ${response.status} error`);
}
} catch (error) {
console.log(error);
}
}
fetchint = setInterval(fetchRequestWithError, 10*1000);
uvicorn 서버 실행
flask 서버 실행
지금은 일정 시간마다 paste들이 계속해서 출력되고 있다.
최대 10개까지 출력하되, 최근 글이 가장 위로 오게 해보자.
-- 과제 --
// mybp/static/mainjs.js
let pasteCount = 0;
async function fetchRequestWithError() {
try {
const url = `http://localhost:8080/pastebin/api/pastes/`;
const response = await fetch(url);
if (response.status >= 200 && response.status < 400) {
const data = await response.json();
for (var key in data) {
// 현재 렌더링하고자 하는 paste는 key+1번째 paste이다.
// 지금까지 렌더링 된 paste의 개수는 pasteCount.
// pasteCount번째 paste들은 중복되어 출력하지 않고 continue로 넘어간다.
if (key < pasteCount) {
continue;
}
pasteCount += 1;
ndiv = document.createElement('div');
ndiv.innerHTML = `<h3>${data[key]['title']} </h3><p> ${data[key]['content']}</p><hr>`;
pdiv = document.getElementById('pastes');
// appendChild 및 append는 요소 맨 마지막에 넣는 함수이므로,
// 요소 맨 앞에 추가하는 prepend 함수를 사용한다.
pdiv.prepend(ndiv);
// 현재까지 렌더링 된 paste의 수가 6개를 넘기면
// 맨 아래 출력된 paste를 제거한다.
if (pasteCount > 6) {
pdiv.removeChild(pdiv.lastElementChild);
}
}
} else {
console.log(`${response.statusText}: ${response.status} error`);
}
} catch (error) {
console.log(error);
}
}
fetchint = setInterval(fetchRequestWithError, 10 * 1000);
728x90
반응형
LIST