Kenneth Bruen
3 years ago
16 changed files with 230 additions and 39 deletions
@ -1,33 +0,0 @@
|
||||
from flask import Flask, json, request, jsonify |
||||
|
||||
from cache import CachedData |
||||
|
||||
app = Flask(__name__) |
||||
|
||||
@app.route('/') |
||||
def root(): |
||||
return 'Test' |
||||
|
||||
train_data_cache = {} |
||||
|
||||
@app.route('/train/<int:train_no>') |
||||
def get_train_info(train_no: int): |
||||
def get_data(): |
||||
print(f'Cache miss for {train_no}') |
||||
from scraper.scraper import scrape |
||||
use_yesterday = False |
||||
return scrape(train_no, use_yesterday=use_yesterday) |
||||
if train_no not in train_data_cache: |
||||
train_data_cache[train_no] = CachedData(get_data, validity=1000 * 30) |
||||
data, fetch_time = train_data_cache[train_no]() |
||||
resp = jsonify(data) |
||||
resp.headers['X-Last-Fetched'] = fetch_time.isoformat() |
||||
return resp |
||||
|
||||
@app.route('/trains') |
||||
def get_trains(): |
||||
return jsonify(list(train_data_cache.keys())) |
||||
|
||||
if __name__ == '__main__': |
||||
print('Starting debug server on port 5001') |
||||
app.run(port=5000) |
@ -0,0 +1,85 @@
|
||||
# Globals |
||||
stations = [] |
||||
trains = [] |
||||
|
||||
# Examples |
||||
example_station = { |
||||
'name': 'Gară', |
||||
'stoppedAtBy': [123, 456] |
||||
} |
||||
|
||||
example_train = { |
||||
'rank': 'IR', |
||||
'numberString': '74', |
||||
'number': 74, |
||||
'company': 'CFR Călători' |
||||
} |
||||
|
||||
# Init |
||||
|
||||
import json |
||||
import os |
||||
from os import path, stat |
||||
from .utils import take_while |
||||
|
||||
DB_DIR = os.environ.get('DB_DIR', '') or './db' |
||||
if not path.exists(DB_DIR): |
||||
os.mkdir(DB_DIR) |
||||
|
||||
STATIONS_FILE = path.join(DB_DIR, 'stations.json') |
||||
|
||||
if path.exists(STATIONS_FILE): |
||||
with open(STATIONS_FILE) as f: |
||||
stations = json.load(f) |
||||
|
||||
TRAINS_FILE = path.join(DB_DIR, 'trains.json') |
||||
|
||||
if path.exists(TRAINS_FILE): |
||||
with open(TRAINS_FILE) as f: |
||||
trains = json.load(f) |
||||
|
||||
def found_train(rank: str, number: str, company: str) -> int: |
||||
number_int = int(''.join(take_while(lambda s: str(s).isnumeric(), number))) |
||||
try: |
||||
next(filter(lambda tr: tr['number'] == number_int, trains)) |
||||
except StopIteration: |
||||
trains.append({ |
||||
'number': number_int, |
||||
'numberString': number, |
||||
'company': company, |
||||
'rank': rank, |
||||
}) |
||||
with open(TRAINS_FILE, 'w') as f: |
||||
json.dump(trains, f) |
||||
return number_int |
||||
|
||||
def found_station(name: str): |
||||
try: |
||||
next(filter(lambda s: s['name'] == name, stations)) |
||||
except StopIteration: |
||||
stations.append({ |
||||
'name': name, |
||||
'stoppedAtBy': [], |
||||
}) |
||||
stations.sort(key=lambda s: len(s['stoppedAtBy']), reverse=True) |
||||
with open(STATIONS_FILE, 'w') as f: |
||||
json.dump(stations, f) |
||||
|
||||
def found_train_at_station(station_name: str, train_number: int): |
||||
found_station(station_name) |
||||
for i in range(len(stations)): |
||||
if stations[i]['name'] == station_name: |
||||
if train_number not in stations[i]['stoppedAtBy']: |
||||
stations[i]['stoppedAtBy'].append(train_number) |
||||
stations.sort(key=lambda s: len(s['stoppedAtBy']), reverse=True) |
||||
with open(STATIONS_FILE, 'w') as f: |
||||
json.dump(stations, f) |
||||
break |
||||
|
||||
def on_train_data(train_data: dict): |
||||
train_no = found_train(train_data['rank'], train_data['number'], train_data['operator']) |
||||
for station in train_data['stations']: |
||||
found_train_at_station(station['name'], train_no) |
||||
|
||||
def on_train_lookup_failure(train_no: int): |
||||
pass |
@ -0,0 +1,53 @@
|
||||
print(f'Server {__name__=}') |
||||
|
||||
import datetime |
||||
from flask import Flask, json, request, jsonify |
||||
|
||||
from .cache import CachedData |
||||
|
||||
app = Flask(__name__) |
||||
|
||||
from .v2 import v2 |
||||
app.register_blueprint(v2.bp) |
||||
|
||||
@app.route('/') |
||||
def root(): |
||||
return 'Test' |
||||
|
||||
train_data_cache = {} |
||||
|
||||
@app.route('/train/<int:train_no>') |
||||
def get_train_info(train_no: int): |
||||
def get_data(): |
||||
from .scraper.scraper import scrape |
||||
use_yesterday = False |
||||
result = scrape(train_no, use_yesterday=use_yesterday) |
||||
|
||||
from . import db |
||||
db.on_train_data(result) |
||||
|
||||
# Convert to v1 |
||||
# datetime ISO string to hh:mm |
||||
for i in range(len(result['stations'])): |
||||
if result['stations'][i]['arrival']: |
||||
date = datetime.datetime.fromisoformat(result['stations'][i]['arrival']['scheduleTime']) |
||||
result['stations'][i]['arrival']['scheduleTime'] = f'{date.hour}:{date.minute:02}' |
||||
if result['stations'][i]['departure']: |
||||
date = datetime.datetime.fromisoformat(result['stations'][i]['departure']['scheduleTime']) |
||||
result['stations'][i]['departure']['scheduleTime'] = f'{date.hour}:{date.minute:02}' |
||||
|
||||
return result |
||||
if train_no not in train_data_cache: |
||||
train_data_cache[train_no] = CachedData(get_data, validity=1000 * 30) |
||||
data, fetch_time = train_data_cache[train_no]() |
||||
resp = jsonify(data) |
||||
resp.headers['X-Last-Fetched'] = fetch_time.isoformat() |
||||
return resp |
||||
|
||||
@app.route('/trains') |
||||
def get_trains(): |
||||
return jsonify(list(train_data_cache.keys())) |
||||
|
||||
if __name__ == '__main__': |
||||
print('Starting debug server on port 5001') |
||||
app.run(port=5000) |
@ -0,0 +1,18 @@
|
||||
def take_while(predicate, input): |
||||
for element in input: |
||||
if not predicate(element): |
||||
break |
||||
yield element |
||||
|
||||
_NO_DEFAULT = object() |
||||
|
||||
def check_yes_no(input: str, default=_NO_DEFAULT, considered_yes=None) -> bool: |
||||
input = str(input).strip().lower() |
||||
if not input: |
||||
if default == _NO_DEFAULT: |
||||
raise Exception('Empty input with no default') |
||||
return default |
||||
if not considered_yes: |
||||
considered_yes = ['y', 'yes', 't', 'true', '1'] |
||||
return input in considered_yes |
||||
|
@ -0,0 +1,32 @@
|
||||
from flask import Blueprint, jsonify, request |
||||
|
||||
from .. import db |
||||
from ..cache import CachedData |
||||
from ..utils import check_yes_no |
||||
|
||||
bp = Blueprint('v2', __name__, url_prefix='/v2') |
||||
|
||||
@bp.get('/trains') |
||||
def get_known_trains(): |
||||
return jsonify(db.trains) |
||||
|
||||
@bp.get('/stations') |
||||
def get_known_stations(): |
||||
return jsonify(db.stations) |
||||
|
||||
train_data_cache = {} |
||||
|
||||
@bp.route('/train/<int:train_no>') |
||||
def get_train_info(train_no: int): |
||||
use_yesterday = check_yes_no(request.args.get('use_yesterday', ''), default=False) |
||||
def get_data(): |
||||
from ..scraper.scraper import scrape |
||||
result = scrape(train_no, use_yesterday=use_yesterday) |
||||
db.on_train_data(result) |
||||
return result |
||||
if train_no not in train_data_cache: |
||||
train_data_cache[(train_no, use_yesterday)] = CachedData(get_data, validity=1000 * 30) |
||||
data, fetch_time = train_data_cache[(train_no, use_yesterday)]() |
||||
resp = jsonify(data) |
||||
resp.headers['X-Last-Fetched'] = fetch_time.isoformat() |
||||
return resp |
Loading…
Reference in new issue