Revert "First steps toward search"

This reverts commit 87034967ae.
This commit is contained in:
Nathan Byrd 2023-02-10 21:34:49 -06:00
parent 87034967ae
commit 6466220b6d
5 changed files with 2409 additions and 3672 deletions

View File

@ -14,17 +14,17 @@ const ActivityPubObject = require('./object');
const { ActivityStreamMediaType } = require('./const'); const { ActivityStreamMediaType } = require('./const');
const apDb = require('../database').dbs.activitypub; const apDb = require('../database').dbs.activitypub;
const Config = require('../config').get; const Config = require('../config').get;
const parseFullName = require('parse-full-name').parseFullName;
// deps // deps
const _ = require('lodash'); const _ = require('lodash');
const mimeTypes = require('mime-types'); const mimeTypes = require('mime-types');
const { getJson } = require('../http_util.js'); const { getJson } = require('../http_util.js');
const { getISOTimestampString } = require('../database.js'); const { getISOTimestampString } = require('../database.js');
const moment = require('moment');
const paths = require('path'); const paths = require('path');
const ActorCacheExpiration = moment.duration(15, 'days');
const ActorCacheMaxAgeDays = 125; // hasn't been used in >= 125 days, nuke it. const ActorCacheMaxAgeDays = 125; // hasn't been used in >= 125 days, nuke it.
const MaxSearchResults = 10; // Maximum number of results to show for a search
// default context for Actor's // default context for Actor's
const DefaultContext = ActivityPubObject.makeContext(['https://w3id.org/security/v1'], { const DefaultContext = ActivityPubObject.makeContext(['https://w3id.org/security/v1'], {
@ -167,10 +167,14 @@ module.exports = class Actor extends ActivityPubObject {
} }
}; };
Actor._fromCache(id, (err, actor, subject) => { Actor._fromCache(id, (err, actor, subject, needsRefresh) => {
if (!err) { if (!err) {
// cache hit // cache hit
callback(null, actor, subject); callback(null, actor, subject);
if (!needsRefresh) {
return;
}
} }
// Cache miss or needs refreshed; Try to do so now // Cache miss or needs refreshed; Try to do so now
@ -190,76 +194,21 @@ module.exports = class Actor extends ActivityPubObject {
// cache our entry // cache our entry
if (actor) { if (actor) {
apDb.run(
'DELETE FROM actor_cache_search WHERE actor_id=?',
[id],
err => {
if (err) {
Log.warn(
{ err: err },
'Error deleting previous actor_cache_search'
);
}
}
);
apDb.run( apDb.run(
`REPLACE INTO actor_cache (actor_id, actor_json, subject, timestamp) `REPLACE INTO actor_cache (actor_id, actor_json, subject, timestamp)
VALUES (?, ?, ?, ?);`, VALUES (?, ?, ?, ?);`,
[id, JSON.stringify(actor), subject, getISOTimestampString()], [id, JSON.stringify(actor), subject, getISOTimestampString()],
err => { err => {
if (err) { if (err) {
Log.warn( // :TODO: log me
{ err: err },
'Error replacing into the actor cache'
);
} }
} }
); );
const searchNames = this._parseSearchNames(actor);
if (searchNames.length > 0) {
const searchStatement = apDb.prepare(
'INSERT INTO actor_cache_search (actor_id, search_name) VALUES (?, ?)'
);
searchNames.forEach(name => {
searchStatement.run([id, name], err => {
if (err) {
Log.warn(
{ err: err },
'Error inserting into actor cache search'
);
}
});
});
}
} }
}); });
}); });
} }
static _parseSearchNames(actor) {
const searchNames = [];
if (!_.isEmpty(actor.preferredUsername)) {
searchNames.push(actor.preferredUsername);
}
const name = parseFullName(actor.name);
if (!_.isEmpty(name.first)) {
searchNames.push(name.first);
}
if (!_.isEmpty(name.last)) {
searchNames.push(name.last);
}
if (!_.isEmpty(name.nick)) {
searchNames.push(name.nick);
}
return searchNames;
}
static actorCacheMaintenanceTask(args, cb) { static actorCacheMaintenanceTask(args, cb) {
const enabled = _.get( const enabled = _.get(
Config(), Config(),
@ -271,10 +220,10 @@ module.exports = class Actor extends ActivityPubObject {
apDb.run( apDb.run(
`DELETE FROM actor_cache `DELETE FROM actor_cache
WHERE DATETIME(timestamp) < DATETIME("now", "-${ActorCacheMaxAgeDays} day");`, WHERE DATETIME(timestamp) > DATETIME("now", "+${ActorCacheMaxAgeDays}");`,
err => { err => {
if (err) { if (err) {
Log.warn({ err: err }, 'Error clearing old cache entries.'); // :TODO: log me
} }
return cb(null); // always non-fatal return cb(null); // always non-fatal
@ -282,40 +231,6 @@ module.exports = class Actor extends ActivityPubObject {
); );
} }
static fromSearch(searchString, cb) {
// first try to find an exact match
this.fromId(searchString, (err, remoteActor) => {
if (!err) {
return cb(null, [remoteActor]);
} else {
Log.info({ err: err }, 'Not able to find based on id');
}
});
let returnRows = [];
// If not found, try searching database for known actors
apDb.each(
`SELECT actor_cache.actor_json
FROM actor_cache INNER JOIN actor_cache_search ON actor_cache.actor_id = actor_cache_search.actor_id
WHERE actor_cache_search.search_name like '%'||?||'%'
LIMIT ${MaxSearchResults}`,
(err, row) => {
if (err) {
Log.warn({ err: err }, 'error retrieving search results');
return cb(err, []);
}
this._fromJsonToActor(row.actor_json, (err, actor) => {
if (err) {
Log.warn({ err: err }, 'error converting search results');
return cb(err, []);
}
returnRows.push(actor);
});
}
);
return cb(null, returnRows);
}
static _fromRemoteQuery(id, cb) { static _fromRemoteQuery(id, cb) {
const headers = { const headers = {
Accept: ActivityStreamMediaType, Accept: ActivityStreamMediaType,
@ -338,10 +253,9 @@ module.exports = class Actor extends ActivityPubObject {
static _fromCache(actorIdOrSubject, cb) { static _fromCache(actorIdOrSubject, cb) {
apDb.get( apDb.get(
`SELECT actor_json, subject `SELECT actor_json, subject, timestamp
FROM actor_cache FROM actor_cache
WHERE actor_id = ? OR subject = ? WHERE actor_id = ? OR subject = ?
AND DATETIME(timestamp) > DATETIME("now", "-${ActorCacheMaxAgeDays} day")
LIMIT 1;`, LIMIT 1;`,
[actorIdOrSubject, actorIdOrSubject], [actorIdOrSubject, actorIdOrSubject],
(err, row) => { (err, row) => {
@ -353,31 +267,27 @@ module.exports = class Actor extends ActivityPubObject {
return cb(Errors.DoesNotExist()); return cb(Errors.DoesNotExist());
} }
this._fromJsonToActor(row.actor_json, (err, actor) => { const timestamp = moment(row.timestamp);
if (err) { const needsRefresh = moment().isAfter(
return cb(err); timestamp.add(ActorCacheExpiration)
} );
const subject = row.subject || actor.id;
return cb(null, actor, subject); const obj = ActivityPubObject.fromJsonString(row.actor_json);
}); if (!obj || !obj.isValid()) {
return cb(Errors.Invalid('Failed to create ActivityPub object'));
}
const actor = new Actor(obj);
if (!actor.isValid()) {
return cb(Errors.Invalid('Failed to create Actor object'));
}
const subject = row.subject || actor.id;
return cb(null, actor, subject, needsRefresh);
} }
); );
} }
static _fromJsonToActor(actorJson, cb) {
const obj = ActivityPubObject.fromJsonString(actorJson);
if (!obj || !obj.isValid()) {
return cb(Errors.Invalid('Failed to create ActivityPub object'));
}
const actor = new Actor(obj);
if (!actor.isValid()) {
return cb(Errors.Invalid('Failed to create Actor object'));
}
return cb(null, actor);
}
static _fromWebFinger(actorQuery, cb) { static _fromWebFinger(actorQuery, cb) {
queryWebFinger(actorQuery, (err, res) => { queryWebFinger(actorQuery, (err, res) => {
if (err) { if (err) {

View File

@ -480,8 +480,7 @@ dbs.message.run(
actor_json VARCHAR NOT NULL, -- Actor document actor_json VARCHAR NOT NULL, -- Actor document
subject VARCHAR, -- Subject obtained from WebFinger, e.g. @Username@some.domain subject VARCHAR, -- Subject obtained from WebFinger, e.g. @Username@some.domain
timestamp DATETIME NOT NULL, -- Timestamp in which this Actor was cached timestamp DATETIME NOT NULL, -- Timestamp in which this Actor was cached
preferredUsername VARCHAR, -- Denormalized username for search
name VARCHAR, -- Denormalized actor name for search
UNIQUE(actor_id) UNIQUE(actor_id)
);` );`
); );
@ -491,25 +490,6 @@ dbs.message.run(
ON actor_cache (actor_id);` ON actor_cache (actor_id);`
); );
// Denormalized actor information for search
dbs.activitypub.run(
`CREATE TABLE IF NOT EXISTS actor_cache_search (
actor_id VARCHAR NOT NULL, -- Fully qualified Actor ID/URL
search_name VARCHAR, -- Name to search
CONSTRAINT actor_cache_search_actor_cache_fk FOREIGN KEY(actor_id) REFERENCES actor_cache(actor_id) ON DELETE CASCADE
);`
);
dbs.activitypub.run(
`CREATE INDEX IF NOT EXISTS actor_cache_search_actor_id_index0
ON actor_cache_search (actor_id);`
);
dbs.activitypub.run(
`CREATE INDEX IF NOT EXISTS actor_cache_search_name_index0
ON actor_cache_search (search_name);`
);
// ActivityPub Collections of various types such as followers, following, likes, ... // ActivityPub Collections of various types such as followers, following, likes, ...
dbs.activitypub.run( dbs.activitypub.run(
`CREATE TABLE IF NOT EXISTS collection ( `CREATE TABLE IF NOT EXISTS collection (

1166
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -57,7 +57,6 @@
"node-pty": "0.10.1", "node-pty": "0.10.1",
"nodemailer": "6.7.7", "nodemailer": "6.7.7",
"otplib": "11.0.1", "otplib": "11.0.1",
"parse-full-name": "^1.2.6",
"qrcode-generator": "^1.4.4", "qrcode-generator": "^1.4.4",
"rlogin": "^1.0.0", "rlogin": "^1.0.0",
"sane": "5.0.1", "sane": "5.0.1",

4746
yarn.lock

File diff suppressed because it is too large Load Diff