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_dummy import DummyProvider # noqa: F401
1114from provider_partstack import Partstack
1215
1316app = Flask (__name__ )
1417app .wsgi_app = ProxyFix (app .wsgi_app , x_proto = 1 , x_host = 1 )
1518
1619PARTS_MAX_COUNT = 10
20+ PARTS_CACHE_MAX_AGE = 30 * 24 * 3600 # 30 days due to quota limits
1721PARTS_QUERY_TIMEOUT = 8.0
1822
1923
@@ -47,6 +51,20 @@ def _write_status(key_values):
4751 app .logger .critical (str (e ))
4852
4953
54+ def _get_db ():
55+ db = getattr (g , '_db' , None )
56+ if db is None :
57+ db = g ._database = sqlite3 .connect ('/config/db.sqlite' )
58+ return db
59+
60+
61+ @app .teardown_appcontext
62+ def _close_db (exception ):
63+ db = getattr (g , '_db' , None )
64+ if db is not None :
65+ db .close ()
66+
67+
5068@app .route ('/api/v1/parts' , methods = ['GET' ])
5169def parts ():
5270 enabled = _get_config ('parts_operational' , False )
@@ -72,21 +90,37 @@ def parts_query():
7290 parts = payload ['parts' ][:PARTS_MAX_COUNT ]
7391 parts = [dict (mpn = p ['mpn' ], manufacturer = p ['manufacturer' ]) for p in parts ]
7492
75- # Fetch parts from provider.
93+ # Prepare database.
94+ db = Database (_get_db (), app .logger )
95+
96+ # Fetch parts from providers.
7697 status = dict ()
77- provider = Partstack (_get_config ('parts_query_url' ),
78- _get_config ('parts_query_token' ),
79- PARTS_QUERY_TIMEOUT , app .logger )
80- provider .fetch (parts , status )
98+ cache_hits = 0
99+ providers = [
100+ PartsCache (db , max_age = PARTS_CACHE_MAX_AGE ),
101+ Partstack (_get_config ('parts_query_url' ),
102+ _get_config ('parts_query_token' ),
103+ PARTS_QUERY_TIMEOUT , db , app .logger ),
104+ ]
105+ for provider in providers :
106+ cache_hits += provider .fetch (parts , status )
81107
82108 # Handle status changes.
83109 if len (status ):
84110 _write_status (status )
85111
86112 # Complete parts which were not found.
113+ found = 0
87114 for part in parts :
88115 if 'results' not in part :
89116 part ['results' ] = 0
117+ if part ['results' ] > 0 :
118+ found += 1
119+
120+ # Store request in database.
121+ app .logger .debug (f"Queried { len (parts )} parts, { cache_hits } from cache: "
122+ f"{ found } found, { len (parts ) - found } not found" )
123+ db .add_parts_request (len (parts ), cache_hits , found )
90124
91125 # Return response.
92126 return dict (parts = parts )
0 commit comments