22
33import json
44import os
5+ import sqlite3
56
67from flask import (Flask , g , make_response , request , send_from_directory ,
78 url_for )
89from werkzeug .middleware .proxy_fix import ProxyFix
910
11+ from database import Database
12+ from provider_cache import PartsCache
1013from provider_partstack import Partstack
1114
1215app = Flask (__name__ )
1316app .wsgi_app = ProxyFix (app .wsgi_app , x_proto = 1 , x_host = 1 )
1417
1518PARTS_MAX_COUNT = 10
19+ PARTS_CACHE_MAX_AGE = 30 * 24 * 3600 # 30 days due to quota limits
1620PARTS_QUERY_TIMEOUT = 8.0
1721
1822
@@ -46,6 +50,20 @@ def _write_status(key_values):
4650 app .logger .critical (str (e ))
4751
4852
53+ def _get_db ():
54+ db = getattr (g , '_db' , None )
55+ if db is None :
56+ db = g ._database = sqlite3 .connect ('/config/db.sqlite' )
57+ return db
58+
59+
60+ @app .teardown_appcontext
61+ def _close_db (exception ):
62+ db = getattr (g , '_db' , None )
63+ if db is not None :
64+ db .close ()
65+
66+
4967@app .route ('/api/v1/parts' , methods = ['GET' ])
5068def parts ():
5169 enabled = _get_config ('parts_operational' , False )
@@ -71,21 +89,37 @@ def parts_query():
7189 parts = payload ['parts' ][:PARTS_MAX_COUNT ]
7290 parts = [dict (mpn = p ['mpn' ], manufacturer = p ['manufacturer' ]) for p in parts ]
7391
74- # Fetch parts from provider.
92+ # Prepare database.
93+ db = Database (_get_db (), app .logger )
94+
95+ # Fetch parts from providers.
7596 status = dict ()
76- provider = Partstack (_get_config ('parts_query_url' ),
77- _get_config ('parts_query_token' ),
78- PARTS_QUERY_TIMEOUT , app .logger )
79- provider .fetch (parts , status )
97+ cache_hits = 0
98+ providers = [
99+ PartsCache (db , max_age = PARTS_CACHE_MAX_AGE ),
100+ Partstack (_get_config ('parts_query_url' ),
101+ _get_config ('parts_query_token' ),
102+ PARTS_QUERY_TIMEOUT , db , app .logger ),
103+ ]
104+ for provider in providers :
105+ cache_hits += provider .fetch (parts , status )
80106
81107 # Handle status changes.
82108 if len (status ):
83109 _write_status (status )
84110
85111 # Complete parts which were not found.
112+ found = 0
86113 for part in parts :
87114 if 'results' not in part :
88115 part ['results' ] = 0
116+ if part ['results' ] > 0 :
117+ found += 1
118+
119+ # Store request in database.
120+ app .logger .debug (f"Queried { len (parts )} parts, { cache_hits } from cache: "
121+ f"{ found } found, { len (parts ) - found } not found" )
122+ db .add_parts_request (len (parts ), cache_hits , found )
89123
90124 # Return response.
91125 return dict (parts = parts )
0 commit comments