2019-11-12 14:39:26 +00:00
|
|
|
/*
|
2019-11-18 09:16:29 +00:00
|
|
|
Copyright 2019 The Matrix.org Foundation C.I.C.
|
2019-11-12 14:39:26 +00:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2019-11-19 11:52:12 +00:00
|
|
|
import EventIndexPeg from "./indexing/EventIndexPeg";
|
2019-12-20 21:13:46 +00:00
|
|
|
import {MatrixClientPeg} from "./MatrixClientPeg";
|
2019-11-12 14:39:26 +00:00
|
|
|
|
|
|
|
function serverSideSearch(term, roomId = undefined) {
|
|
|
|
let filter;
|
|
|
|
if (roomId !== undefined) {
|
2019-11-18 09:48:18 +00:00
|
|
|
// XXX: it's unintuitive that the filter for searching doesn't have
|
|
|
|
// the same shape as the v2 filter API :(
|
2019-11-12 14:39:26 +00:00
|
|
|
filter = {
|
|
|
|
rooms: [roomId],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-11-13 09:30:38 +00:00
|
|
|
const searchPromise = MatrixClientPeg.get().searchRoomEvents({
|
2019-11-18 09:55:02 +00:00
|
|
|
filter,
|
|
|
|
term,
|
2019-11-12 14:39:26 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return searchPromise;
|
|
|
|
}
|
|
|
|
|
2019-11-18 09:56:57 +00:00
|
|
|
async function combinedSearch(searchTerm) {
|
2019-11-13 09:10:35 +00:00
|
|
|
// Create two promises, one for the local search, one for the
|
|
|
|
// server-side search.
|
|
|
|
const serverSidePromise = serverSideSearch(searchTerm);
|
2019-11-18 09:56:57 +00:00
|
|
|
const localPromise = localSearch(searchTerm);
|
2019-11-13 09:10:35 +00:00
|
|
|
|
|
|
|
// Wait for both promises to resolve.
|
|
|
|
await Promise.all([serverSidePromise, localPromise]);
|
|
|
|
|
|
|
|
// Get both search results.
|
|
|
|
const localResult = await localPromise;
|
|
|
|
const serverSideResult = await serverSidePromise;
|
|
|
|
|
|
|
|
// Combine the search results into one result.
|
|
|
|
const result = {};
|
|
|
|
|
|
|
|
// Our localResult and serverSideResult are both ordered by
|
2019-11-18 09:57:23 +00:00
|
|
|
// recency separately, when we combine them the order might not
|
2019-11-13 09:10:35 +00:00
|
|
|
// be the right one so we need to sort them.
|
|
|
|
const compare = (a, b) => {
|
|
|
|
const aEvent = a.context.getEvent().event;
|
|
|
|
const bEvent = b.context.getEvent().event;
|
|
|
|
|
|
|
|
if (aEvent.origin_server_ts >
|
|
|
|
bEvent.origin_server_ts) return -1;
|
|
|
|
if (aEvent.origin_server_ts <
|
|
|
|
bEvent.origin_server_ts) return 1;
|
|
|
|
return 0;
|
2019-11-12 14:39:26 +00:00
|
|
|
};
|
|
|
|
|
2019-11-13 09:10:35 +00:00
|
|
|
result.count = localResult.count + serverSideResult.count;
|
|
|
|
result.results = localResult.results.concat(
|
|
|
|
serverSideResult.results).sort(compare);
|
|
|
|
result.highlights = localResult.highlights.concat(
|
|
|
|
serverSideResult.highlights);
|
2019-11-12 14:39:26 +00:00
|
|
|
|
2020-05-29 14:32:57 +00:00
|
|
|
result.seshatQuery = localResult.seshatQuery;
|
|
|
|
result.serverSideNextBatch = serverSideResult.next_batch;
|
|
|
|
result._query = serverSideResult._query;
|
|
|
|
|
|
|
|
// We need the next batch to be set for the client to know that it can
|
|
|
|
// paginate further.
|
|
|
|
if (serverSideResult.next_batch) {
|
|
|
|
result.next_batch = serverSideResult.next_batch;
|
|
|
|
} else {
|
|
|
|
result.next_batch = localResult.next_batch;
|
|
|
|
}
|
|
|
|
|
2019-11-13 09:10:35 +00:00
|
|
|
return result;
|
|
|
|
}
|
2019-11-12 14:39:26 +00:00
|
|
|
|
2019-11-18 09:56:57 +00:00
|
|
|
async function localSearch(searchTerm, roomId = undefined) {
|
2019-11-13 09:10:35 +00:00
|
|
|
const searchArgs = {
|
|
|
|
search_term: searchTerm,
|
|
|
|
before_limit: 1,
|
|
|
|
after_limit: 1,
|
|
|
|
order_by_recency: true,
|
2019-11-13 10:02:54 +00:00
|
|
|
room_id: undefined,
|
2019-11-13 09:10:35 +00:00
|
|
|
};
|
2019-11-12 14:39:26 +00:00
|
|
|
|
2019-11-13 09:10:35 +00:00
|
|
|
if (roomId !== undefined) {
|
|
|
|
searchArgs.room_id = roomId;
|
|
|
|
}
|
2019-11-12 14:39:26 +00:00
|
|
|
|
2020-03-20 10:38:43 +00:00
|
|
|
const emptyResult = {
|
2020-05-29 09:44:08 +00:00
|
|
|
seshatQuery: searchArgs,
|
2020-03-20 10:38:43 +00:00
|
|
|
results: [],
|
|
|
|
highlights: [],
|
|
|
|
};
|
|
|
|
|
|
|
|
if (searchTerm === "") return emptyResult;
|
|
|
|
|
2019-11-13 09:10:35 +00:00
|
|
|
const eventIndex = EventIndexPeg.get();
|
2019-11-12 14:39:26 +00:00
|
|
|
|
2019-11-13 09:10:35 +00:00
|
|
|
const localResult = await eventIndex.search(searchArgs);
|
2020-05-29 09:44:08 +00:00
|
|
|
emptyResult.seshatQuery.next_batch = localResult.next_batch;
|
2019-11-12 14:39:26 +00:00
|
|
|
|
2019-11-13 09:10:35 +00:00
|
|
|
const response = {
|
|
|
|
search_categories: {
|
|
|
|
room_events: localResult,
|
|
|
|
},
|
|
|
|
};
|
2019-11-12 14:39:26 +00:00
|
|
|
|
2020-05-29 14:32:57 +00:00
|
|
|
return MatrixClientPeg.get()._processRoomEventsSearch(emptyResult, response);
|
2020-05-29 09:44:08 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 14:32:57 +00:00
|
|
|
async function localPagination(searchResult) {
|
2020-05-29 09:44:08 +00:00
|
|
|
const eventIndex = EventIndexPeg.get();
|
|
|
|
|
2020-05-29 14:32:57 +00:00
|
|
|
const searchArgs = searchResult.seshatQuery;
|
2020-05-29 09:44:08 +00:00
|
|
|
|
|
|
|
const localResult = await eventIndex.search(searchArgs);
|
2020-05-29 14:32:57 +00:00
|
|
|
searchResult.seshatQuery.next_batch = localResult.next_batch;
|
2020-05-29 09:44:08 +00:00
|
|
|
|
|
|
|
const response = {
|
|
|
|
search_categories: {
|
|
|
|
room_events: localResult,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const result = MatrixClientPeg.get()._processRoomEventsSearch(searchResult, response);
|
|
|
|
searchResult.pendingRequest = null;
|
2019-11-13 09:10:35 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-05-29 14:32:57 +00:00
|
|
|
/**
|
|
|
|
* Combine the local and server search results
|
|
|
|
*/
|
|
|
|
function combineResults(previousSearchResult, localResult = undefined, serverSideResult = undefined) {
|
|
|
|
// // cachedResults = previousSearchResult.cachedResults;
|
|
|
|
// if (localResult) {
|
|
|
|
// previousSearchResult.seshatQuery.next_batch = localResult.next_batch;
|
|
|
|
// }
|
|
|
|
const compare = (a, b) => {
|
|
|
|
const aEvent = a.result;
|
|
|
|
const bEvent = b.result;
|
|
|
|
|
|
|
|
if (aEvent.origin_server_ts >
|
|
|
|
bEvent.origin_server_ts) return -1;
|
|
|
|
if (aEvent.origin_server_ts <
|
|
|
|
bEvent.origin_server_ts) return 1;
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
const result = {};
|
|
|
|
|
|
|
|
result.count = previousSearchResult.count;
|
|
|
|
|
|
|
|
if (localResult && serverSideResult) {
|
|
|
|
result.results = localResult.results.concat(serverSideResult.results).sort(compare);
|
|
|
|
result.highlights = localResult.highlights.concat(serverSideResult.highlights);
|
|
|
|
} else if (localResult) {
|
|
|
|
result.results = localResult.results;
|
|
|
|
result.highlights = localResult.highlights;
|
|
|
|
} else {
|
|
|
|
result.results = serverSideResult.results;
|
|
|
|
result.highlights = serverSideResult.highlights;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (localResult) {
|
|
|
|
previousSearchResult.seshatQuery.next_batch = localResult.next_batch;
|
|
|
|
result.next_batch = localResult.next_batch;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (serverSideResult && serverSideResult.next_batch) {
|
|
|
|
previousSearchResult.serverSideNextBatch = serverSideResult.next_batch;
|
|
|
|
result.next_batch = serverSideResult.next_batch;
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log("HELLOO COMBINING RESULTS", localResult, serverSideResult, result);
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
async function combinedPagination(searchResult) {
|
|
|
|
const eventIndex = EventIndexPeg.get();
|
|
|
|
const client = MatrixClientPeg.get();
|
|
|
|
|
|
|
|
console.log("HELLOOO WORLD");
|
|
|
|
|
|
|
|
const searchArgs = searchResult.seshatQuery;
|
|
|
|
|
|
|
|
let localResult;
|
|
|
|
let serverSideResult;
|
|
|
|
|
|
|
|
if (searchArgs.next_batch) {
|
|
|
|
localResult = await eventIndex.search(searchArgs);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (searchResult.serverSideNextBatch) {
|
|
|
|
const body = {body: searchResult._query, next_batch: searchResult.serverSideNextBatch};
|
|
|
|
serverSideResult = await client.search(body);
|
|
|
|
}
|
|
|
|
|
|
|
|
const combinedResult = combineResults(searchResult, localResult, serverSideResult.search_categories.room_events);
|
|
|
|
|
|
|
|
const response = {
|
|
|
|
search_categories: {
|
|
|
|
room_events: combinedResult,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const result = client._processRoomEventsSearch(searchResult, response);
|
|
|
|
|
|
|
|
console.log("HELLO NEW RESULT", searchResult);
|
|
|
|
|
|
|
|
searchResult.pendingRequest = null;
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2019-11-13 09:10:35 +00:00
|
|
|
function eventIndexSearch(term, roomId = undefined) {
|
2019-11-12 14:39:26 +00:00
|
|
|
let searchPromise;
|
|
|
|
|
|
|
|
if (roomId !== undefined) {
|
|
|
|
if (MatrixClientPeg.get().isRoomEncrypted(roomId)) {
|
|
|
|
// The search is for a single encrypted room, use our local
|
|
|
|
// search method.
|
2019-11-18 09:56:57 +00:00
|
|
|
searchPromise = localSearch(term, roomId);
|
2019-11-12 14:39:26 +00:00
|
|
|
} else {
|
|
|
|
// The search is for a single non-encrypted room, use the
|
|
|
|
// server-side search.
|
|
|
|
searchPromise = serverSideSearch(term, roomId);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Search across all rooms, combine a server side search and a
|
|
|
|
// local search.
|
2019-11-18 09:56:57 +00:00
|
|
|
searchPromise = combinedSearch(term);
|
2019-11-12 14:39:26 +00:00
|
|
|
}
|
|
|
|
|
2019-11-13 09:30:38 +00:00
|
|
|
return searchPromise;
|
2019-11-12 14:39:26 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 09:44:08 +00:00
|
|
|
function eventIndexSearchPagination(searchResult) {
|
|
|
|
const client = MatrixClientPeg.get();
|
|
|
|
|
2020-05-29 14:32:57 +00:00
|
|
|
const seshatQuery = searchResult.seshatQuery;
|
|
|
|
const serverQuery = searchResult._query;
|
|
|
|
|
|
|
|
if (!seshatQuery) {
|
2020-05-29 09:44:08 +00:00
|
|
|
return client.backPaginateRoomEventsSearch(searchResult);
|
2020-05-29 14:32:57 +00:00
|
|
|
} else if (!serverQuery) {
|
|
|
|
const promise = localPagination(searchResult);
|
2020-05-29 09:44:08 +00:00
|
|
|
searchResult.pendingRequest = promise;
|
2020-05-29 14:32:57 +00:00
|
|
|
|
2020-05-29 09:44:08 +00:00
|
|
|
return promise;
|
2020-05-29 14:32:57 +00:00
|
|
|
} else {
|
|
|
|
const promise = combinedPagination(searchResult);
|
|
|
|
searchResult.pendingRequest = promise;
|
|
|
|
|
|
|
|
return promise
|
2020-05-29 09:44:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function searchPagination(searchResult) {
|
|
|
|
const eventIndex = EventIndexPeg.get();
|
|
|
|
const client = MatrixClientPeg.get();
|
|
|
|
|
|
|
|
if (searchResult.pendingRequest) return searchResult.pendingRequest;
|
|
|
|
|
|
|
|
if (eventIndex === null) return client.backPaginateRoomEventsSearch(searchResult);
|
|
|
|
else return eventIndexSearchPagination(searchResult);
|
|
|
|
}
|
|
|
|
|
2019-11-12 14:39:26 +00:00
|
|
|
export default function eventSearch(term, roomId = undefined) {
|
|
|
|
const eventIndex = EventIndexPeg.get();
|
|
|
|
|
|
|
|
if (eventIndex === null) return serverSideSearch(term, roomId);
|
|
|
|
else return eventIndexSearch(term, roomId);
|
|
|
|
}
|