Store chatlogs in binary and text formats
If chat logs are stored in an endless plain-text file, they're going to be a pain to parse. If they're stored in a binary file, they're a pain for the user to `grep` or go through manually, but they're easier to parse. Why not both? Logs are now stored with a BMessage (with BStringLists) in the 'logs' attribute, and the plain-text logs in the file itself. The attribute will only store 20 messages, but the file itself will be appended to forever. The logs directory also changed, from ~/config/settings/Caya/Cache/Logs to ~/config/settings/Caya/Logs. Useful functions for reading/writing messages to and from an attribute were borrowed from BePodder's libfunky. :-)
This commit is contained in:
parent
fe99f3d83a
commit
dc3fdd65c8
|
@ -1,11 +1,8 @@
|
|||
/*
|
||||
* Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved.
|
||||
* Copyright 2014, Funky Idea Software
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
|
@ -15,6 +12,8 @@
|
|||
#include <IconUtils.h>
|
||||
#include <Path.h>
|
||||
|
||||
#include <kernel/fs_attr.h>
|
||||
|
||||
#include "CayaUtils.h"
|
||||
|
||||
|
||||
|
@ -129,8 +128,11 @@ CayaCachePath()
|
|||
const char*
|
||||
CayaLogPath(const char* signature, const char* subsignature)
|
||||
{
|
||||
BPath path(CayaCachePath());
|
||||
path.Append("Logs");
|
||||
BPath path;
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||
return NULL;
|
||||
|
||||
path.Append("Caya/Logs");
|
||||
path.Append(signature);
|
||||
|
||||
if (BString(signature) != BString(subsignature)
|
||||
|
@ -175,6 +177,62 @@ CayaTintColor(rgb_color color, int severity)
|
|||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReadAttributeData(BNode* node, const char* name, char** buffer, int32 *size) {
|
||||
attr_info info;
|
||||
status_t ret = node->GetAttrInfo(name, &info);
|
||||
|
||||
if (ret == B_OK) {
|
||||
*buffer = (char *)calloc(info.size, sizeof(char));
|
||||
ret = node->ReadAttr(name, info.type, 0, *buffer, info.size);
|
||||
|
||||
if (ret > B_OK) {
|
||||
*size = ret;
|
||||
ret = B_OK;
|
||||
}
|
||||
else
|
||||
free(*buffer);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WriteAttributeMessage(BNode* node, const char* name, BMessage* data)
|
||||
{
|
||||
BMallocIO malloc;
|
||||
status_t ret=data->Flatten(&malloc);
|
||||
|
||||
if( ret == B_OK) {
|
||||
ret = node->WriteAttr(name,B_ANY_TYPE,0,malloc.Buffer(),malloc.BufferLength());
|
||||
|
||||
if(ret > B_OK)
|
||||
ret=B_OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReadAttributeMessage(BNode* node, const char* name, BMessage* data)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
int32 size = 0;
|
||||
|
||||
status_t ret = ReadAttributeData(node,name,&buffer,&size);
|
||||
|
||||
if(size>0 && buffer!=NULL) {
|
||||
BMemoryIO mem(buffer,size);
|
||||
ret = data->Unflatten(&mem);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
status_t
|
||||
|
|
|
@ -24,9 +24,13 @@ const char* CayaAccountPath(const char* signature, const char* subsignature);
|
|||
const char* CayaCachePath();
|
||||
const char* CayaLogPath(const char* signature, const char* subsignature);
|
||||
|
||||
// Will return a tinted color― light or dark― based on brightness.
|
||||
rgb_color CayaTintColor(rgb_color color, int severity);
|
||||
|
||||
// Borrowed from BePodder's own libfunky
|
||||
status_t ReadAttributeData(BNode* node, const char* name, char** buffer, int32 *size);
|
||||
status_t WriteAttributeMessage(BNode* node, const char* name, BMessage* data);
|
||||
status_t ReadAttributeMessage(BNode* node, const char* name, BMessage* data);
|
||||
|
||||
extern "C" status_t our_image(image_info& image);
|
||||
|
||||
|
||||
|
|
|
@ -173,11 +173,9 @@ Conversation::GetView()
|
|||
if (fLooper->Protocol()->SaveLogs() == false)
|
||||
return fChatView;
|
||||
|
||||
BStringList logs = _GetChatLogs();
|
||||
BMessage logMsg(IM_MESSAGE);
|
||||
logMsg.AddInt32("im_what", IM_LOGS_RECEIVED);
|
||||
logMsg.AddStrings("body", logs);
|
||||
fChatView->MessageReceived(&logMsg);
|
||||
BMessage logMsg;
|
||||
if (_GetChatLogs(&logMsg) == B_OK)
|
||||
fChatView->MessageReceived(&logMsg);
|
||||
|
||||
RegisterObserver(fChatView);
|
||||
return fChatView;
|
||||
|
@ -266,8 +264,32 @@ Conversation::_LogChatMessage(BMessage* msg)
|
|||
fDateFormatter.Format(date, time(0), B_SHORT_DATE_FORMAT, B_MEDIUM_TIME_FORMAT);
|
||||
|
||||
BString id = msg->FindString("user_id");
|
||||
BString uname;
|
||||
BString body = msg->FindString("body");
|
||||
|
||||
// Binary logs
|
||||
// TODO: Don't hardcode 21, expose maximum as a setting
|
||||
BStringList users, bodies;
|
||||
|
||||
BMessage logMsg;
|
||||
if (_GetChatLogs(&logMsg) == B_OK) {
|
||||
logMsg.FindStrings("body", &bodies);
|
||||
logMsg.FindStrings("user_id", &users);
|
||||
bodies.Remove(21);
|
||||
users.Remove(21);
|
||||
bodies.Add(body, 0);
|
||||
users.Add(id, 0);
|
||||
}
|
||||
|
||||
BMessage newLogMsg(IM_MESSAGE);
|
||||
newLogMsg.AddInt32("im_what", IM_LOGS_RECEIVED);
|
||||
newLogMsg.AddStrings("body", bodies);
|
||||
newLogMsg.AddStrings("user_id", users);
|
||||
|
||||
BFile logFile(fLogPath.Path(), B_READ_WRITE | B_OPEN_AT_END | B_CREATE_FILE);
|
||||
WriteAttributeMessage(&logFile, "logs", &newLogMsg);
|
||||
|
||||
// Plain-text logs
|
||||
BString uname;
|
||||
if (id.IsEmpty() == false)
|
||||
uname = UserById(id)->GetName();
|
||||
else
|
||||
|
@ -278,37 +300,21 @@ Conversation::_LogChatMessage(BMessage* msg)
|
|||
logLine << "] ";
|
||||
logLine << uname;
|
||||
logLine << ": ";
|
||||
logLine << msg->FindString("body");
|
||||
logLine << body;
|
||||
logLine << "\n";
|
||||
|
||||
|
||||
// TODO: Don't hardcode 21, expose maximum as a setting
|
||||
BStringList logs = _GetChatLogs();
|
||||
logs.Remove(21);
|
||||
logs.Add(logLine, 0);
|
||||
|
||||
BMessage newLogMsg;
|
||||
newLogMsg.AddStrings("log", logs);
|
||||
|
||||
BFile logFile(fLogPath.Path(), B_READ_WRITE | B_CREATE_FILE);
|
||||
newLogMsg.Flatten(&logFile);
|
||||
logFile.Write(logLine.String(), logLine.Length());
|
||||
}
|
||||
|
||||
|
||||
BStringList
|
||||
Conversation::_GetChatLogs()
|
||||
status_t
|
||||
Conversation::_GetChatLogs(BMessage* msg)
|
||||
{
|
||||
_EnsureLogPath();
|
||||
|
||||
BFile logFile(fLogPath.Path(), B_READ_WRITE | B_CREATE_FILE);
|
||||
BMessage logMsg;
|
||||
BStringList logs;
|
||||
|
||||
if (logMsg.Unflatten(&logFile) == B_OK) {
|
||||
logMsg.FindStrings("log", &logs);
|
||||
}
|
||||
|
||||
return logs;
|
||||
return ReadAttributeMessage(&logFile, "logs", msg);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
|
||||
private:
|
||||
void _LogChatMessage(BMessage* msg);
|
||||
BStringList _GetChatLogs();
|
||||
status_t _GetChatLogs(BMessage* msg);
|
||||
void _EnsureLogPath();
|
||||
|
||||
User* _EnsureUser(BMessage* msg);
|
||||
|
|
|
@ -275,31 +275,25 @@ ConversationView::_AppendOrEnqueueMessage(BMessage* msg)
|
|||
void
|
||||
ConversationView::_AppendMessage(BMessage* msg)
|
||||
{
|
||||
BStringList users, bodies;
|
||||
if (msg->FindStrings("body", &bodies) != B_OK
|
||||
|| msg->FindStrings("user_id", &users) != B_OK)
|
||||
return;
|
||||
|
||||
BString message = msg->FindString("body");
|
||||
BString id = msg->FindString("user_id");
|
||||
BString uname = "";
|
||||
for (int i = bodies.CountStrings(); i >= 0; i--) {
|
||||
User* sender = fConversation->UserById(users.StringAt(i));
|
||||
BString sender_name;
|
||||
BString body = bodies.StringAt(i);
|
||||
|
||||
if (id.IsEmpty() == false) {
|
||||
User* sender = fConversation->UserById(id);
|
||||
if (sender != NULL)
|
||||
sender_name = sender->GetName();
|
||||
|
||||
if (sender == NULL || (uname = sender->GetName()) == NULL)
|
||||
uname = id;
|
||||
}
|
||||
if (sender_name.IsEmpty() == true) {
|
||||
fReceiveView->AppendGenericMessage(body.String());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg->FindInt32("im_what") == IM_MESSAGE_SENT)
|
||||
fReceiveView->AppendOwnMessage(message.String());
|
||||
|
||||
else if (uname.IsEmpty() == false)
|
||||
fReceiveView->AppendOtherMessage(uname.String(), message.String());
|
||||
|
||||
else {
|
||||
BStringList bodies;
|
||||
if (msg->FindStrings("body", &bodies) != B_OK)
|
||||
return;
|
||||
|
||||
for (int i = bodies.CountStrings(); i >= 0; i--)
|
||||
fReceiveView->AppendGenericMessage(bodies.StringAt(i).String());
|
||||
fReceiveView->AppendOtherMessage(sender_name.String(), body.String());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -688,7 +688,7 @@ JabberHandler::_MessageSent(const char* id, const char* subject,
|
|||
{
|
||||
BMessage msg(IM_MESSAGE);
|
||||
msg.AddInt32("im_what", IM_MESSAGE_SENT);
|
||||
msg.AddString("user_id", id);
|
||||
msg.AddString("user_id", fJid.bare().c_str());
|
||||
msg.AddString("chat_id", id);
|
||||
msg.AddString("subject", subject);
|
||||
msg.AddString("body", body);
|
||||
|
|
Ŝarĝante…
Reference in New Issue