aboutsummaryrefslogtreecommitdiff
path: root/libdino/src/service
diff options
context:
space:
mode:
Diffstat (limited to 'libdino/src/service')
-rw-r--r--libdino/src/service/content_item_accumulator.vala224
-rw-r--r--libdino/src/service/file_manager.vala37
-rw-r--r--libdino/src/service/message_storage.vala32
3 files changed, 272 insertions, 21 deletions
diff --git a/libdino/src/service/content_item_accumulator.vala b/libdino/src/service/content_item_accumulator.vala
new file mode 100644
index 00000000..9fc852b2
--- /dev/null
+++ b/libdino/src/service/content_item_accumulator.vala
@@ -0,0 +1,224 @@
+using Gee;
+
+using Dino.Entities;
+using Xmpp;
+
+namespace Dino {
+
+public class ContentItemAccumulator : StreamInteractionModule, Object {
+ public static ModuleIdentity<ContentItemAccumulator> IDENTITY = new ModuleIdentity<ContentItemAccumulator>("content_item_accumulator");
+ public string id { get { return IDENTITY.id; } }
+
+ public signal void new_item();
+
+ private StreamInteractor stream_interactor;
+ private Gee.List<ContentFilter> filters = new ArrayList<ContentFilter>();
+ private HashMap<ContentItemCollection, Conversation> collection_conversations = new HashMap<ContentItemCollection, Conversation>();
+
+ public static void start(StreamInteractor stream_interactor) {
+ ContentItemAccumulator m = new ContentItemAccumulator(stream_interactor);
+ stream_interactor.add_module(m);
+ }
+
+ public ContentItemAccumulator(StreamInteractor stream_interactor) {
+ this.stream_interactor = stream_interactor;
+
+ stream_interactor.get_module(MessageProcessor.IDENTITY).message_received.connect(on_new_message);
+ stream_interactor.get_module(MessageProcessor.IDENTITY).message_sent.connect(on_new_message);
+ stream_interactor.get_module(FileManager.IDENTITY).received_file.connect(insert_file_transfer);
+ }
+
+ public void init(Conversation conversation, ContentItemCollection item_collection) {
+ collection_conversations[item_collection] = conversation;
+ }
+
+ public Gee.List<ContentItem> populate_latest(ContentItemCollection item_collection, Conversation conversation, int n) {
+ Gee.TreeSet<ContentItem> items = new Gee.TreeSet<ContentItem>(ContentItem.compare);
+
+ Gee.List<Entities.Message>? messages = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages(conversation, n);
+ if (messages != null) {
+ foreach (Entities.Message message in messages) {
+ items.add(new MessageItem(message, conversation));
+ }
+ }
+ Gee.List<FileTransfer> transfers = stream_interactor.get_module(FileManager.IDENTITY).get_latest_transfers(conversation.account, conversation.counterpart, n);
+ foreach (FileTransfer transfer in transfers) {
+ items.add(new FileItem(transfer));
+ }
+
+ BidirIterator<ContentItem> iter = items.bidir_iterator();
+ iter.last();
+ int i = 0;
+ while (i < n && iter.has_previous()) {
+ iter.previous();
+ i++;
+ }
+ Gee.List<ContentItem> ret = new ArrayList<ContentItem>();
+ do {
+ ret.add(iter.get());
+ } while(iter.next());
+ return ret;
+ }
+
+ public Gee.List<ContentItem> populate_before(ContentItemCollection item_collection, Conversation conversation, ContentItem item, int n) {
+ Gee.TreeSet<ContentItem> items = new Gee.TreeSet<ContentItem>(ContentItem.compare);
+
+ Gee.List<Entities.Message>? messages = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages_before_message(conversation, item.display_time, n);
+ if (messages != null) {
+ foreach (Entities.Message message in messages) {
+ items.add(new MessageItem(message, conversation));
+ }
+ }
+ Gee.List<FileTransfer> transfers = stream_interactor.get_module(FileManager.IDENTITY).get_transfers_before(conversation.account, conversation.counterpart, item.display_time, n);
+ foreach (FileTransfer transfer in transfers) {
+ items.add(new FileItem(transfer));
+ }
+
+ BidirIterator<ContentItem> iter = items.bidir_iterator();
+ iter.last();
+ int i = 0;
+ while (i < n && iter.has_previous()) {
+ iter.previous();
+ i++;
+ }
+ Gee.List<ContentItem> ret = new ArrayList<ContentItem>();
+ do {
+ ret.add(iter.get());
+ } while(iter.next());
+ return ret;
+ }
+
+ public void populate_after(Conversation conversation, ContentItem item, int n) {
+
+ }
+
+ public void add_filter(ContentFilter content_filter) {
+ filters.add(content_filter);
+ }
+
+ private void on_new_message(Message message, Conversation conversation) {
+ foreach (ContentItemCollection collection in collection_conversations.keys) {
+ if (collection_conversations[collection].equals(conversation)) {
+ MessageItem item = new MessageItem(message, conversation);
+ insert_item(collection, item);
+ }
+ }
+ }
+
+ private void insert_file_transfer(FileTransfer file_transfer) {
+ foreach (ContentItemCollection collection in collection_conversations.keys) {
+ Conversation conversation = collection_conversations[collection];
+ if (conversation.account.equals(file_transfer.account) && conversation.counterpart.equals_bare(file_transfer.counterpart)) {
+ FileItem item = new FileItem(file_transfer);
+ insert_item(collection, item);
+ }
+ }
+ }
+
+ private void insert_item(ContentItemCollection item_collection, ContentItem content_item) {
+ bool insert = true;
+ foreach (ContentFilter filter in filters) {
+ if (filter.discard(content_item)) {
+ insert = false;
+ }
+ }
+ if (insert) {
+ item_collection.insert_item(content_item);
+ }
+ }
+}
+
+public interface ContentItemCollection : Object {
+ public abstract void insert_item(ContentItem item);
+ public abstract void remove_item(ContentItem item);
+}
+
+public interface ContentFilter : Object {
+ public abstract bool discard(ContentItem content_item);
+}
+
+public abstract class ContentItem : Object {
+ public virtual string type_ { get; set; }
+ public virtual Jid? jid { get; set; default=null; }
+ public virtual DateTime? sort_time { get; set; default=null; }
+ public virtual double seccondary_sort_indicator { get; set; }
+ public virtual DateTime? display_time { get; set; default=null; }
+ public virtual Encryption? encryption { get; set; default=null; }
+ public virtual Entities.Message.Marked? mark { get; set; default=null; }
+
+ public static int compare(ContentItem a, ContentItem b) {
+ int res = a.sort_time.compare(b.sort_time);
+ if (res == 0) {
+ res = a.display_time.compare(b.display_time);
+ }
+ if (res == 0) {
+ res = a.seccondary_sort_indicator - b.seccondary_sort_indicator > 0 ? 1 : -1;
+ }
+ return res;
+ }
+}
+
+public class MessageItem : ContentItem {
+ public const string TYPE = "message";
+ public override string type_ { get; set; default=TYPE; }
+
+ public Message message;
+ public Conversation conversation;
+
+ public MessageItem(Message message, Conversation conversation) {
+ this.message = message;
+ this.conversation = conversation;
+
+ this.jid = message.from;
+ this.sort_time = message.local_time;
+ this.seccondary_sort_indicator = message.id + 0.0845;
+ this.display_time = message.time;
+ this.encryption = message.encryption;
+ this.mark = message.marked;
+
+ WeakRef weak_message = WeakRef(message);
+ message.notify["marked"].connect(() => {
+ Message? m = weak_message.get() as Message;
+ if (m == null) return;
+ mark = m.marked;
+ });
+ }
+}
+
+public class FileItem : ContentItem {
+ public const string TYPE = "file";
+ public override string type_ { get; set; default=TYPE; }
+
+ public FileTransfer file_transfer;
+ public Conversation conversation;
+
+ public FileItem(FileTransfer file_transfer) {
+ this.file_transfer = file_transfer;
+
+ this.jid = file_transfer.direction == FileTransfer.DIRECTION_SENT ? file_transfer.account.bare_jid.with_resource(file_transfer.account.resourcepart) : file_transfer.counterpart;
+ this.sort_time = file_transfer.time;
+ this.seccondary_sort_indicator = file_transfer.id + 0.2903;
+ this.display_time = file_transfer.time;
+ this.encryption = file_transfer.encryption;
+ this.mark = file_to_message_state(file_transfer.state);
+ file_transfer.notify["state"].connect_after(() => {
+ this.mark = file_to_message_state(file_transfer.state);
+ });
+ }
+
+ private Entities.Message.Marked file_to_message_state(FileTransfer.State state) {
+ switch (state) {
+ case FileTransfer.State.IN_PROCESS:
+ return Entities.Message.Marked.UNSENT;
+ case FileTransfer.State.COMPLETE:
+ return Entities.Message.Marked.NONE;
+ case FileTransfer.State.NOT_STARTED:
+ return Entities.Message.Marked.UNSENT;
+ case FileTransfer.State.FAILED:
+ return Entities.Message.Marked.WONTSEND;
+ }
+ assert_not_reached();
+ }
+}
+
+}
diff --git a/libdino/src/service/file_manager.vala b/libdino/src/service/file_manager.vala
index 3def24af..667076dd 100644
--- a/libdino/src/service/file_manager.vala
+++ b/libdino/src/service/file_manager.vala
@@ -78,6 +78,37 @@ public class FileManager : StreamInteractionModule, Object {
return false;
}
+ public Gee.List<FileTransfer> get_latest_transfers(Account account, Jid counterpart, int n) {
+ Qlite.QueryBuilder select = db.file_transfer.select()
+ .with(db.file_transfer.counterpart_id, "=", db.get_jid_id(counterpart))
+ .with(db.file_transfer.account_id, "=", account.id)
+ .order_by(db.file_transfer.local_time, "DESC")
+ .limit(n);
+
+ Gee.List<FileTransfer> ret = new ArrayList<FileTransfer>();
+ foreach (Qlite.Row row in select) {
+ FileTransfer file_transfer = new FileTransfer.from_row(db, row, get_storage_dir());
+ ret.insert(0, file_transfer);
+ }
+ return ret;
+ }
+
+ public Gee.List<FileTransfer> get_transfers_before(Account account, Jid counterpart, DateTime before, int n) {
+ Qlite.QueryBuilder select = db.file_transfer.select()
+ .with(db.file_transfer.counterpart_id, "=", db.get_jid_id(counterpart))
+ .with(db.file_transfer.account_id, "=", account.id)
+ .with(db.file_transfer.local_time, "<", (long)before.to_unix())
+ .order_by(db.file_transfer.local_time, "DESC")
+ .limit(n);
+
+ Gee.List<FileTransfer> ret = new ArrayList<FileTransfer>();
+ foreach (Qlite.Row row in select) {
+ FileTransfer file_transfer = new FileTransfer.from_row(db, row, get_storage_dir());
+ ret.insert(0, file_transfer);
+ }
+ return ret;
+ }
+
public Gee.List<FileTransfer> get_file_transfers(Account account, Jid counterpart, DateTime after, DateTime before) {
Qlite.QueryBuilder select = db.file_transfer.select()
.with(db.file_transfer.counterpart_id, "=", db.get_jid_id(counterpart))
@@ -88,11 +119,7 @@ public class FileManager : StreamInteractionModule, Object {
Gee.List<FileTransfer> ret = new ArrayList<FileTransfer>();
foreach (Qlite.Row row in select) {
- FileTransfer file_transfer = new FileTransfer.from_row(db, row);
- File file = File.new_for_path(Path.build_filename(get_storage_dir(), file_transfer.path ?? file_transfer.file_name));
- try {
- file_transfer.input_stream = file.read();
- } catch (Error e) { }
+ FileTransfer file_transfer = new FileTransfer.from_row(db, row, get_storage_dir());
ret.insert(0, file_transfer);
}
return ret;
diff --git a/libdino/src/service/message_storage.vala b/libdino/src/service/message_storage.vala
index 35e05074..906693a3 100644
--- a/libdino/src/service/message_storage.vala
+++ b/libdino/src/service/message_storage.vala
@@ -51,23 +51,23 @@ public class MessageStorage : StreamInteractionModule, Object {
return null;
}
- public Gee.List<Message>? get_messages_before_message(Conversation? conversation, Message message, int count = 20) {
- SortedSet<Message>? before = messages[conversation].head_set(message);
- if (before != null && before.size >= count) {
- Gee.List<Message> ret = new ArrayList<Message>(Message.equals_func);
- Iterator<Message> iter = before.iterator();
- iter.next();
- for (int from_index = before.size - count; iter.has_next() && from_index > 0; from_index--) iter.next();
- while(iter.has_next()) {
- Message m = iter.get();
- ret.add(m);
- iter.next();
- }
- return ret;
- } else {
- Gee.List<Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, Util.get_message_type_for_conversation(conversation), count, message.local_time);
+ public Gee.List<Message>? get_messages_before_message(Conversation? conversation, DateTime before, int count = 20) {
+// SortedSet<Message>? before = messages[conversation].head_set(message);
+// if (before != null && before.size >= count) {
+// Gee.List<Message> ret = new ArrayList<Message>(Message.equals_func);
+// Iterator<Message> iter = before.iterator();
+// iter.next();
+// for (int from_index = before.size - count; iter.has_next() && from_index > 0; from_index--) iter.next();
+// while(iter.has_next()) {
+// Message m = iter.get();
+// ret.add(m);
+// iter.next();
+// }
+// return ret;
+// } else {
+ Gee.List<Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, Util.get_message_type_for_conversation(conversation), count, before);
return db_messages;
- }
+// }
}
public Message? get_message_by_id(string stanza_id, Conversation conversation) {