feedless/app/lib/queries.js

357 lines
8.6 KiB
JavaScript
Raw Normal View History

const pull = require("pull-stream");
const cat = require("pull-cat");
const debug = require("debug")("queries");
const paramap = require("pull-paramap");
const latestOwnerValue = (ssbServer, { key, dest }) =>
new Promise((resolve, reject) => {
let value = null;
pull(
ssbServer.query.read({
reverse: true,
query: [
{
$filter: {
value: {
author: dest,
content: { type: "about", about: dest },
},
2020-04-05 14:41:06 +02:00
},
},
],
}),
pull.filter((msg) => {
return (
msg.value.content &&
key in msg.value.content &&
!(msg.value.content[key] && msg.value.content[key].remove)
);
}),
pull.take(1),
pull.drain(
(msg) => {
value = msg.value.content[key];
2020-04-05 14:41:06 +02:00
},
(err) => {
if (err) return reject(err);
if (!value) {
ssbServer.about
.latestValue({ key, dest })
.then(resolve)
.catch(reject);
} else {
resolve(value);
}
}
)
);
});
2020-04-05 14:41:06 +02:00
2020-04-06 10:16:50 +02:00
const mapProfiles = (ssbServer) => (data, callback) => {
const authorPromise = getProfile(ssbServer, data.value.author);
const contactPromise =
data.value.content.type == "contact" &&
getProfile(ssbServer, data.value.content.contact);
return Promise.all([authorPromise, contactPromise])
.then(([author, contact]) => {
data.value.authorProfile = author;
if (contact) {
data.value.content.contactProfile = contact;
}
callback(null, data);
})
.catch((err) => callback(err, null));
};
const getPosts = (ssbServer, profile) =>
debug("Fetching posts") ||
new Promise((resolve, reject) => {
pull(
// @ts-ignore
cat([
ssbServer.query.read({
reverse: true,
query: [
{
$filter: {
value: {
2020-04-08 08:44:23 +02:00
private: { $not: true },
content: {
root: profile.id,
},
},
},
},
],
limit: 100,
}),
ssbServer.query.read({
reverse: true,
query: [
{
$filter: {
value: {
author: profile.id,
2020-04-08 08:44:23 +02:00
private: { $not: true },
content: {
type: "post",
root: { $not: true },
},
},
},
},
],
limit: 100,
}),
]),
pull.filter((msg) => msg.value.content.type == "post"),
paramap(mapProfiles(ssbServer)),
pull.collect((err, msgs) => {
debug("Done fetching posts");
const entries = msgs.map((x) => x.value);
if (err) return reject(err);
return resolve(entries);
})
);
});
const getVanishingMessages = async (ssbServer, profile) => {
debug("Fetching vanishing messages");
const messagesPromise = new Promise((resolve, reject) => {
2020-04-08 08:44:23 +02:00
pull(
// @ts-ignore
cat([
ssbServer.query.read({
reverse: true,
query: [
{
$filter: {
value: {
private: true,
content: {
root: profile.id,
},
},
},
},
],
limit: 100,
}),
ssbServer.query.read({
reverse: true,
query: [
{
$filter: {
value: {
private: true,
content: {
type: "post",
root: { $not: true },
},
},
},
},
],
limit: 100,
}),
]),
pull.filter(
(msg) =>
msg.value.content.type == "post" &&
(msg.value.content.root ||
msg.value.content.recps.includes(profile.id))
),
paramap(mapProfiles(ssbServer)),
pull.collect((err, msgs) => {
if (err) return reject(err);
return resolve(msgs);
})
);
});
2020-04-08 08:44:23 +02:00
const deletedPromise = new Promise((resolve, reject) => {
pull(
ssbServer.query.read({
reverse: true,
query: [
{
$filter: {
value: {
author: profile.id,
content: {
type: "delete",
},
},
},
},
],
}),
pull.collect((err, msgs) => {
2020-04-08 08:44:23 +02:00
if (err) return reject(err);
return resolve(Object.values(msgs));
2020-04-08 08:44:23 +02:00
})
);
});
const [messages, deleted] = await Promise.all([
messagesPromise,
deletedPromise,
]);
const deletedIds = deleted.map((x) => x.value.content.dest);
debug("Done fetching vanishing messages");
return messages.filter((m) => !deletedIds.includes(m.key));
};
2020-04-05 14:51:25 +02:00
const searchPeople = (ssbServer, search) =>
debug("Searching people") ||
new Promise((resolve, reject) => {
pull(
ssbServer.query.read({
reverse: true,
query: [
{
$filter: {
value: {
content: {
type: "about",
name: { $is: "string" },
},
},
},
},
],
2020-04-05 14:41:06 +02:00
}),
pull.filter((msg) => {
2020-04-05 14:51:25 +02:00
return (
msg.value.content &&
msg.value.author == msg.value.content.about &&
msg.value.content.name.includes(search)
);
}),
pull.collect((err, msgs) => {
debug("Done searching people");
2020-04-05 14:41:06 +02:00
const entries = msgs.map((x) => x.value);
if (err) return reject(err);
2020-04-05 14:41:06 +02:00
return resolve(Object.values(entries));
})
);
});
const getFriends = (ssbServer, profile) =>
debug("Fetching friends") ||
new Promise((resolve, reject) => {
pull(
ssbServer.query.read({
reverse: true,
query: [
{
$filter: {
value: {
author: profile.id,
content: {
type: "contact",
},
},
},
},
],
limit: 20,
}),
paramap(mapProfiles(ssbServer)),
pull.collect((err, msgs) => {
debug("Done fetching friends");
const entries = msgs.map((x) => x.value);
if (err) return reject(err);
return resolve(entries);
})
);
});
2020-04-11 18:03:58 +02:00
const getFriendshipStatus = async (ssbServer, source, dest) => {
debug("Fetching friendship status");
const [isFollowing, isFollowingBack] = await Promise.all([
ssbServer.friends.isFollowing({ source: source, dest: dest }),
ssbServer.friends.isFollowing({ source: dest, dest: source }),
]);
let status = "no_relation";
if (isFollowing && isFollowingBack) {
status = "friends";
} else if (isFollowing && !isFollowingBack) {
status = "request_sent";
} else if (!isFollowing && isFollowingBack) {
status = "request_received";
}
return status;
};
const getAllEntries = (ssbServer, query) =>
debug("Fetching All Entries") ||
new Promise((resolve, reject) => {
let queries = [];
if (query.author) {
queries.push({ $filter: { value: { author: query.author } } });
}
if (query.type) {
queries.push({ $filter: { value: { content: { type: query.type } } } });
}
const queryOpts = queries.length > 0 ? { query: queries } : {};
pull(
ssbServer.query.read({
reverse: true,
2020-04-05 14:41:06 +02:00
limit: 500,
...queryOpts,
}),
pull.collect((err, msgs) => {
debug("Done fetching all entries");
if (err) return reject(err);
return resolve(msgs);
})
);
});
let profileCache = {};
const getProfile = async (ssbServer, id) => {
if (profileCache[id]) return profileCache[id];
let getKey = (key) => latestOwnerValue(ssbServer, { key, dest: id });
2020-04-05 20:11:55 +02:00
let [name, image, description] = await Promise.all([
getKey("name"),
getKey("image"),
getKey("description"),
]).catch((err) => {
console.error("Could not retrieve profile for", id, err);
});
let profile = { id, name, image, description };
profileCache[id] = profile;
return profile;
};
setInterval(() => {
debug("Clearing profile cache");
profileCache = {};
}, 5 * 60 * 1000);
module.exports = {
2020-04-06 10:16:50 +02:00
mapProfiles,
getPosts,
2020-04-05 14:51:25 +02:00
searchPeople,
getFriends,
getAllEntries,
getProfile,
2020-04-08 08:44:23 +02:00
getVanishingMessages,
2020-04-11 13:23:17 +02:00
profileCache,
2020-04-11 18:03:58 +02:00
getFriendshipStatus,
};