]> git.mxchange.org Git - fba.git/blob - fba/instances.py
1271048913b147b44c7903f58bc7a1ba6f8953bb
[fba.git] / fba / instances.py
1 # Fedi API Block - An aggregator for fetching blocking data from fediverse nodes
2 # Copyright (C) 2023 Free Software Foundation
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published
6 # by the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17 from fba import fba
18 import sys
19
20 # Found info from node, such as nodeinfo URL, detection mode that needs to be
21 # written to database. Both arrays must be filled at the same time or else
22 # update_instance_data() will fail
23 instance_data = {
24     # Detection mode: 'AUTO_DISCOVERY', 'STATIC_CHECKS' or 'GENERATOR'
25     # NULL means all detection methods have failed (maybe still reachable instance)
26     "detection_mode"     : {},
27     # Found nodeinfo URL
28     "nodeinfo_url"       : {},
29     # Found total peers
30     "total_peers"        : {},
31     # Last fetched instances
32     "last_instance_fetch": {},
33     # Last updated
34     "last_updated"       : {},
35     # Last blocked
36     "last_blocked"       : {},
37     # Last nodeinfo (fetched)
38     "last_nodeinfo"      : {},
39     # Last status code
40     "last_status_code"   : {},
41     # Last error details
42     "last_error_details" : {},
43 }
44
45 def set_instance_data(key: str, domain: str, value: any):
46     # NOISY-DEBUG: print(f"DEBUG: key='{key}',domain='{domain}',value[]='{type(value)}' - CALLED!")
47     if type(key) != str:
48         raise ValueError("Parameter key[]='{type(key)}' is not 'str'")
49     elif key == "":
50         raise ValueError(f"Parameter 'key' cannot be empty")
51     elif type(domain) != str:
52         raise ValueError("Parameter domain[]='{type(domain)}' is not 'str'")
53     elif domain == "":
54         raise ValueError(f"Parameter 'domain' cannot be empty")
55     elif not key in instance_data:
56         raise ValueError(f"key='{key}' not found in instance_data")
57     elif not fba.is_primitive(value):
58         raise ValueError(f"value[]='{type(value)}' is not a primitive type")
59
60     # Set it
61     instance_data[key][domain] = value
62
63     # DEBUG: print("DEBUG: EXIT!")
64
65 def has_pending_instance_data(domain: str) -> bool:
66     # DEBUG: print(f"DEBUG: domain='{domain}' - CALLED!")
67     if type(domain) != str:
68         raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
69     elif domain == "":
70         raise ValueError(f"Parameter 'domain' cannot be empty")
71
72     has_pending = False
73     for key in instance_data:
74         # DEBUG: print(f"DEBUG: key='{key}',domain='{domain}',instance_data[key]()='{len(instance_data[key])}'")
75         if domain in instance_data[key]:
76             has_pending = True
77             break
78
79     # DEBUG: print(f"DEBUG: has_pending='{has_pending}' - EXIT!")
80     return has_pending
81
82 def update_instance_data(domain: str):
83     # DEBUG: print(f"DEBUG: domain={domain} - CALLED!")
84     if type(domain) != str:
85         raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
86     elif domain == "":
87         raise ValueError(f"Parameter 'domain' cannot be empty")
88     elif not has_pending_instance_data(domain):
89         raise Exception(f"Domain '{domain}' has no pending instance data, but function invoked")
90
91     # DEBUG: print(f"DEBUG: Updating nodeinfo for domain='{domain}' ...")
92     sql_string = ''
93     fields = list()
94     for key in instance_data:
95         # DEBUG: print("DEBUG: key:", key)
96         if domain in instance_data[key]:
97            # DEBUG: print(f"DEBUG: Adding '{instance_data[key][domain]}' for key='{key}' ...")
98            fields.append(instance_data[key][domain])
99            sql_string += f" {key} = ?,"
100
101     fields.append(domain)
102
103     if sql_string == '':
104         raise ValueError(f"No fields have been set, but method invoked, domain='{domain}'")
105
106     # DEBUG: print(f"DEBUG: sql_string='{sql_string}',fields()={len(fields)}")
107     sql_string = "UPDATE instances SET" + sql_string + " last_updated = TIME() WHERE domain = ? LIMIT 1"
108     # DEBUG: print("DEBUG: sql_string:", sql_string)
109
110     try:
111         # DEBUG: print("DEBUG: Executing SQL:", sql_string)
112         fba.cursor.execute(sql_string, fields)
113
114         # DEBUG: print(f"DEBUG: Success! (rowcount={fba.cursor.rowcount })")
115         if fba.cursor.rowcount == 0:
116             print(f"WARNING: Did not update any rows: domain='{domain}',fields()={len(fields)} - EXIT!")
117             return
118
119         fba.connection.commit()
120
121         # DEBUG: print("DEBUG: Deleting instance_data for domain:", domain)
122         for key in instance_data:
123             try:
124                 # DEBUG: print("DEBUG: Deleting key:", key)
125                 del instance_data[key][domain]
126             except:
127                 pass
128
129     except BaseException as e:
130         print(f"ERROR: failed SQL query: domain='{domain}',sql_string='{sql_string}',exception[{type(e)}]:'{str(e)}'")
131         sys.exit(255)
132
133     # DEBUG: print("DEBUG: EXIT!")