00001
00002 #include <microfeed/microfeedfeed.h>
00003 #include <microfeed/microfeedmisc.h>
00004 #include <microfeed/microfeeditem.h>
00005 #include <microfeed/microfeedthread.h>
00006 #include <microfeed/microfeederror.h>
00007 #include <microfeed/microfeedprotocol.h>
00008
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <stdio.h>
00012 #include <stdint.h>
00013
00014 typedef struct _SendItemDataData SendItemDataData;
00015
00016 struct _MicrofeedFeed {
00017 unsigned int reference_count;
00018 MicrofeedWeakReference* weak_reference;
00019
00020 char* uri;
00021 MicrofeedPublisher* publisher;
00022 MicrofeedFeedCallbacks callbacks;
00023 void* user_data;
00024 MicrofeedFeedIterator* iterators;
00025 int subscriber_count;
00026 MicrofeedDatabase* database;
00027 MicrofeedDatabaseIndex* database_index;
00028 MicrofeedDatabase* statuses_database;
00029 MicrofeedDatabase* item_data_database;
00030 MicrofeedMutex* mutex;
00031 int updating;
00032 MicrofeedStore* send_item_data_datas;
00033 };
00034
00035 struct _MicrofeedFeedIterator {
00036 MicrofeedFeedIterator* previous;
00037 MicrofeedFeedIterator* next;
00038
00039 MicrofeedFeed* feed;
00040 MicrofeedDatabaseIterator* database_iterator;
00041 int backwards : 1;
00042 int timeline : 1;
00043 };
00044
00045 typedef struct {
00046 MicrofeedFeed* feed;
00047 const char* start_uid;
00048 const char* end_uid;
00049 unsigned int max_count;
00050 const char* bus_name;
00051 } RepublishingData;
00052
00053 typedef struct {
00054 MicrofeedFeed* feed;
00055 MicrofeedItem* existing_item;
00056 MicrofeedItem* new_item;
00057 } ModifyItemData;
00058
00059 struct _SendItemDataData {
00060 MicrofeedFeed* feed;
00061 char* uid;
00062 MicrofeedStore* bus_names;
00063 };
00064
00065 static void index_function(void* key, const size_t key_size, void* data, const size_t data_size, void** index_key, size_t* index_key_size);
00066 static int compare_function(const void* key1, const size_t key1_size, const void* key2, const size_t key2_size);
00067 static void* update_thread_periodical(void* data);
00068 static void* update_thread_user_initiated(void* data);
00069 static void* republish_thread(void* user_data);
00070 static void* send_item_data_thread(void* data);
00071 static void* modify_item_thread(void* user_data);
00072 static void remove_old_items(MicrofeedFeed* feed);
00073 static const char* send_item_data_data_get_uid(SendItemDataData* send_item_data_data);
00074
00075 MicrofeedFeed* microfeed_feed_new(MicrofeedPublisher* publisher, const char* uri, MicrofeedFeedCallbacks* callbacks, void* user_data) {
00076 MicrofeedFeed* feed;
00077 char* name;
00078
00079 feed = (MicrofeedFeed*)microfeed_memory_allocate(MicrofeedFeed);
00080
00081 feed->reference_count = 1;
00082 feed->weak_reference = NULL;
00083
00084 feed->uri = strdup(uri);
00085 feed->publisher = publisher;
00086 feed->iterators = NULL;
00087 feed->callbacks = *callbacks;
00088 feed->user_data = user_data;
00089
00090 feed->database = microfeed_database_environment_get_database(microfeed_publisher_get_database_environment(publisher), uri, compare_function);
00091 feed->database_index = microfeed_database_get_index(feed->database, "uid", index_function);
00092 name = microfeed_util_string_concatenate(uri, ":microfeed.statuses", NULL);
00093 feed->statuses_database = microfeed_database_environment_get_database(microfeed_publisher_get_database_environment(publisher), name, NULL);
00094 free(name);
00095 if (feed->callbacks.download_item_data) {
00096 name = microfeed_util_string_concatenate(uri, ":microfeed.item_data", NULL);
00097 feed->item_data_database = microfeed_database_environment_get_database(microfeed_publisher_get_database_environment(publisher), name, NULL);
00098 free(name);
00099 }
00100 feed->mutex = microfeed_mutex_new();
00101 feed->send_item_data_datas = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp, (MicrofeedStoreGetKeyFunction)send_item_data_data_get_uid);
00102
00103 return feed;
00104 }
00105
00106
00107 void microfeed_feed_free(MicrofeedFeed* feed) {
00108 MicrofeedFeedIterator* iterator;
00109
00110 if (feed->callbacks.destroy) {
00111 feed->callbacks.destroy(feed, feed->user_data);
00112 }
00113
00114 free(feed->uri);
00115 for (iterator = feed->iterators; iterator; iterator = iterator->next) {
00116 iterator->feed = NULL;
00117 }
00118
00119 microfeed_database_unref(feed->database);
00120 microfeed_database_unref(feed->statuses_database);
00121 if (feed->item_data_database) {
00122 microfeed_database_unref(feed->item_data_database);
00123 }
00124 microfeed_mutex_free(feed->mutex);
00125
00126 feed->uri = NULL;
00127 feed->publisher = NULL;
00128 feed->callbacks.destroy = NULL;
00129 feed->callbacks.update = NULL;
00130 feed->subscriber_count = 0;
00131 feed->iterators = NULL;
00132 microfeed_weak_reference_invalidate(feed->weak_reference);
00133 feed->weak_reference = NULL;
00134
00135 free(feed);
00136 }
00137
00138 MicrofeedFeed* microfeed_feed_ref(MicrofeedFeed* feed) {
00139 microfeed_mutex_lock(feed->mutex);
00140
00141 feed->reference_count++;
00142
00143 microfeed_mutex_unlock(feed->mutex);
00144
00145 return feed;
00146 }
00147
00148 void microfeed_feed_unref(MicrofeedFeed* feed) {
00149 microfeed_mutex_lock(feed->mutex);
00150
00151 feed->reference_count--;
00152
00153 if (feed->reference_count == 0) {
00154 microfeed_feed_free(feed);
00155 } else {
00156
00157 microfeed_mutex_unlock(feed->mutex);
00158 }
00159 }
00160
00161 MicrofeedWeakReference* microfeed_feed_get_weak_reference(MicrofeedFeed* feed) {
00162 MicrofeedWeakReference* weak_reference;
00163
00164 microfeed_mutex_lock(feed->mutex);
00165
00166 weak_reference = feed->weak_reference = microfeed_weak_reference_new(feed, feed->weak_reference);
00167
00168 microfeed_mutex_unlock(feed->mutex);
00169
00170 return weak_reference;
00171 }
00172
00173 MicrofeedPublisher* microfeed_feed_get_publisher(MicrofeedFeed* feed) {
00174
00175 return feed->publisher;
00176 }
00177
00178 void microfeed_feed_stop_update(MicrofeedFeed* feed) {
00179 microfeed_mutex_lock(feed->mutex);
00180
00181 if (feed->updating && microfeed_publisher_get_singleton_update_thread(feed->publisher)) {
00182 microfeed_publisher_send_feed_signal(feed->publisher, NULL, "FeedUpdateEnded", feed->uri);
00183 feed->updating = 0;
00184 }
00185
00186 microfeed_mutex_unlock(feed->mutex);
00187 }
00188
00189 void microfeed_feed_replace_item(MicrofeedFeed* feed, MicrofeedItem* item) {
00190 const char* uid;
00191 size_t uid_size;
00192 uint64_t timestamp;
00193 void* key;
00194 size_t key_size;
00195 const void* data;
00196 size_t data_size;
00197 void* existing_key;
00198 size_t existing_key_size;
00199 void* existing_data;
00200 size_t existing_size;
00201 uint64_t existing_timestamp;
00202 void* status_data;
00203 size_t status_data_size;
00204 char status;
00205 MicrofeedItem* existing_item;
00206
00207 microfeed_mutex_lock(feed->mutex);
00208
00209 uid = microfeed_item_get_uid(item);
00210 uid_size = strlen(uid) + 1;
00211 timestamp = (uint64_t)microfeed_item_get_timestamp(item);
00212 key_size = sizeof(uint64_t) + uid_size;
00213 key = (char*)malloc(key_size);
00214 *((uint64_t*)key) = timestamp;
00215 memcpy(key + sizeof(uint64_t), uid, uid_size);
00216 microfeed_item_marshal_properties(item, &data, &data_size);
00217 if (microfeed_database_index_get_data(feed->database_index, uid, uid_size, &existing_key, &existing_key_size, &existing_data, &existing_size)) {
00218 existing_timestamp = *((uint64_t*)existing_key);
00219 if (timestamp != existing_timestamp || data_size != existing_size || memcmp(data, existing_data, existing_size)) {
00220 if (microfeed_database_get_data(feed->statuses_database, uid, uid_size, &status_data, &status_data_size)) {
00221 status = *((char*)status_data);
00222 free(status_data);
00223 if (!(status & (char)MICROFEED_ITEM_STATUS_ACTIVE)) {
00224 status |= (char)(MICROFEED_ITEM_STATUS_ACTIVE);
00225 microfeed_database_replace_data(feed->statuses_database, uid, uid_size, &status, sizeof(char));
00226 }
00227 } else {
00228 status = (char)MICROFEED_ITEM_STATUS_NONE;
00229 }
00230
00231 existing_item = microfeed_item_new(uid, existing_timestamp);
00232 microfeed_item_demarshal_properties(existing_item, existing_data, existing_size);
00233 microfeed_publisher_handle_item_property_change(feed->publisher, existing_item, item);
00234 microfeed_item_free(existing_item);
00235
00236 microfeed_publisher_send_item_signal(feed->publisher, NULL, "ItemChanged", feed->uri, item);
00237
00238 microfeed_database_index_remove_data(feed->database_index, uid, uid_size);
00239
00240 microfeed_database_replace_data(feed->database, key, key_size, data, data_size);
00241 }
00242 free(existing_key);
00243 free(existing_data);
00244 } else {
00245 status = (char)MICROFEED_ITEM_STATUS_ALL;
00246 microfeed_publisher_handle_item_property_change(feed->publisher, NULL, item);
00247 microfeed_publisher_send_item_signal(feed->publisher, NULL, "ItemAdded", feed->uri, item);
00248 microfeed_database_replace_data(feed->database, key, key_size, data, data_size);
00249 microfeed_database_replace_data(feed->statuses_database, uid, uid_size, &status, sizeof(char));
00250 }
00251 free(key);
00252
00253 microfeed_mutex_unlock(feed->mutex);
00254 }
00255
00256 void microfeed_feed_remove_item(MicrofeedFeed* feed, const char* uid) {
00257 size_t uid_size;
00258 void* key;
00259 size_t key_size;
00260 void* data;
00261 size_t data_size;
00262 uint64_t timestamp;
00263 MicrofeedItem* item;
00264
00265 microfeed_mutex_lock(feed->mutex);
00266
00267 uid_size = strlen(uid) + 1;
00268 if (microfeed_database_index_get_data(feed->database_index, uid, uid_size, &key, &key_size, &data, &data_size)) {
00269 timestamp = *((uint64_t*)key);
00270 item = microfeed_item_new(uid, timestamp);
00271 microfeed_item_demarshal_properties(item, data, data_size);
00272 microfeed_publisher_handle_item_property_change(feed->publisher, item, NULL);
00273 microfeed_item_free(item);
00274 free(key);
00275 free(data);
00276
00277 microfeed_database_index_remove_data(feed->database_index, uid, uid_size);
00278 microfeed_database_remove_data(feed->statuses_database, uid, uid_size);
00279 if (feed->item_data_database) {
00280 microfeed_database_remove_data(feed->item_data_database, uid, uid_size);
00281 }
00282 microfeed_publisher_send_item_uid_signal(feed->publisher, NULL, "ItemRemoved", feed->uri, uid);
00283 }
00284
00285 microfeed_mutex_unlock(feed->mutex);
00286 }
00287
00288 void microfeed_feed_add_subscriber(MicrofeedFeed* feed, const char* bus_name) {
00289 microfeed_mutex_lock(feed->mutex);
00290
00291 feed->subscriber_count++;
00292 feed->reference_count++;
00293
00294 microfeed_mutex_unlock(feed->mutex);
00295 }
00296
00297 int microfeed_feed_get_subscriber_count(MicrofeedFeed* feed) {
00298 int subscriber_count;
00299
00300 microfeed_mutex_lock(feed->mutex);
00301
00302 subscriber_count = feed->subscriber_count;
00303
00304 microfeed_mutex_unlock(feed->mutex);
00305
00306 return subscriber_count;
00307 }
00308
00309 MicrofeedItem* microfeed_feed_get_item(MicrofeedFeed* feed, const char* uid) {
00310 void* key;
00311 size_t key_size;
00312 void* data;
00313 size_t data_size;
00314 uint64_t timestamp;
00315 MicrofeedItem* item;
00316
00317 microfeed_mutex_lock(feed->mutex);
00318
00319 if (!microfeed_database_index_get_data(feed->database_index, uid, strlen(uid) + 1, &key, &key_size, &data, &data_size)) {
00320 item = NULL;
00321 } else {
00322 timestamp = *((uint64_t*)key);
00323 item = microfeed_item_new((char*)(key + sizeof(uint64_t)), (time_t)timestamp);
00324 microfeed_item_demarshal_properties(item, data, data_size);
00325 free(data);
00326 }
00327
00328 microfeed_mutex_unlock(feed->mutex);
00329
00330 return item;
00331 }
00332
00333 const char* microfeed_feed_get_uri(MicrofeedFeed* feed) {
00334
00335 return feed->uri;
00336 }
00337
00338 MicrofeedFeedIterator* microfeed_feed_iterate(MicrofeedFeed* feed, const char* start_uid, int backwards) {
00339 MicrofeedFeedIterator* iterator;
00340
00341 microfeed_mutex_lock(feed->mutex);
00342
00343 iterator = (MicrofeedFeedIterator*)microfeed_memory_allocate(MicrofeedFeedIterator);
00344 iterator->feed = feed;
00345 iterator->backwards = backwards;
00346 iterator->timeline = 0;
00347 iterator->database_iterator = microfeed_database_index_iterate(feed->database_index, start_uid, (start_uid ? strlen(start_uid) + 1 : 0), backwards);
00348
00349 if (feed->iterators) {
00350 feed->iterators->previous = iterator;
00351 iterator->next = feed->iterators;
00352 } else {
00353 iterator->next = NULL;
00354 }
00355 iterator->previous = NULL;
00356 feed->iterators = iterator;
00357
00358 microfeed_mutex_unlock(feed->mutex);
00359
00360 return iterator;
00361 }
00362
00363 MicrofeedFeedIterator* microfeed_feed_iterate_timeline(MicrofeedFeed* feed, const time_t start_timestamp, int backwards) {
00364 MicrofeedFeedIterator* iterator;
00365 char* key;
00366
00367 microfeed_mutex_lock(feed->mutex);
00368
00369 iterator = (MicrofeedFeedIterator*)microfeed_memory_allocate(MicrofeedFeedIterator);
00370 iterator->feed = feed;
00371 iterator->backwards = backwards;
00372 iterator->timeline = 1;
00373 if (start_timestamp) {
00374 key = (char*)malloc(sizeof(uint64_t) + 1);
00375 *((uint64_t*)key) = (uint64_t)start_timestamp;
00376 *(key + sizeof(uint64_t)) = 0;
00377 iterator->database_iterator = microfeed_database_iterate(feed->database, key, sizeof(uint64_t) + 1, backwards);
00378 free(key);
00379 } else {
00380 iterator->database_iterator = microfeed_database_iterate(feed->database, NULL, 0, backwards);
00381 }
00382
00383 if (feed->iterators) {
00384 feed->iterators->previous = iterator;
00385 iterator->next = feed->iterators;
00386 } else {
00387 iterator->next = NULL;
00388 }
00389 iterator->previous = NULL;
00390 feed->iterators = iterator;
00391
00392 microfeed_mutex_unlock(feed->mutex);
00393
00394 return iterator;
00395 }
00396
00397 void microfeed_feed_remove_subscriber(MicrofeedFeed* feed, const char* bus_name) {
00398 microfeed_mutex_lock(feed->mutex);
00399
00400 feed->subscriber_count--;
00401 feed->reference_count--;
00402 if (feed->reference_count == 0) {
00403 microfeed_feed_free(feed);
00404 } else {
00405
00406 microfeed_mutex_unlock(feed->mutex);
00407 }
00408 }
00409
00410 void microfeed_feed_update(MicrofeedFeed* feed, const char* bus_name) {
00411 MicrofeedError* error;
00412
00413 microfeed_mutex_lock(feed->mutex);
00414
00415 if (feed->updating) {
00416 if (bus_name) {
00417 microfeed_publisher_send_feed_signal(feed->publisher, bus_name, "FeedUpdateStarted", feed->uri);
00418 }
00419 } else {
00420 feed->updating = 1;
00421 microfeed_publisher_send_feed_signal(feed->publisher, NULL, "FeedUpdateStarted", feed->uri);
00422
00423 if (feed->callbacks.update) {
00424 if (microfeed_publisher_get_singleton_update_thread(feed->publisher)) {
00425 microfeed_mutex_unlock(feed->mutex);
00426
00427 error = feed->callbacks.update(feed, (bus_name ? 1 : 0), feed->user_data);
00428
00429 microfeed_mutex_lock(feed->mutex);
00430
00431 if (error) {
00432 microfeed_publisher_send_error_signal(feed->publisher, NULL, microfeed_error_get_name(error), feed->uri, NULL, microfeed_error_get_message(error));
00433 microfeed_error_free(error);
00434 }
00435 } else {
00436 feed->reference_count++;
00437 if (bus_name) {
00438 microfeed_publisher_queue_thread(feed->publisher, update_thread_user_initiated, feed);
00439 } else {
00440 microfeed_publisher_queue_thread(feed->publisher, update_thread_periodical, feed);
00441 }
00442 }
00443 }
00444 }
00445
00446 microfeed_mutex_unlock(feed->mutex);
00447 }
00448
00449 void microfeed_feed_republish(MicrofeedFeed* feed, const char* start_uid, const char* end_uid, unsigned int max_count, const char* bus_name) {
00450 RepublishingData* data;
00451
00452 data = microfeed_memory_allocate(RepublishingData);
00453 data->feed = feed;
00454 data->start_uid = start_uid;
00455 data->end_uid = end_uid;
00456 data->max_count = max_count;
00457 data->bus_name = bus_name;
00458
00459 microfeed_publisher_queue_thread(feed->publisher, republish_thread, data);
00460 }
00461
00462 int microfeed_feed_unset_item_status(MicrofeedFeed* feed, const char* uid, MicrofeedItemStatus status_to_unset) {
00463 int retval = 0;
00464 size_t uid_size;
00465 void* data;
00466 size_t data_size;
00467 char status;
00468
00469 microfeed_mutex_lock(feed->mutex);
00470
00471 uid_size = strlen(uid) + 1;
00472 if (microfeed_database_get_data(feed->statuses_database, uid, uid_size, &data, &data_size)) {
00473 retval = 1;
00474 status = *((char*)data);
00475 if (status & (char)status_to_unset) {
00476 status &= (char)(~status_to_unset);
00477 microfeed_publisher_send_status_changed_signal(feed->publisher, NULL, feed->uri, uid, status);
00478 if (status) {
00479 microfeed_database_replace_data(feed->statuses_database, uid, uid_size, &status, sizeof(char));
00480 } else {
00481 microfeed_database_remove_data(feed->statuses_database, uid, uid_size);
00482 }
00483 }
00484 }
00485
00486 microfeed_mutex_unlock(feed->mutex);
00487
00488 return retval;
00489 }
00490
00491 void microfeed_feed_unset_item_statuses(MicrofeedFeed* feed, const char* start_uid, const char* end_uid, MicrofeedItemStatus status_to_unset) {
00492 size_t uid_size;
00493 MicrofeedDatabaseIterator* iterator;
00494 const void* key;
00495 size_t key_size;
00496 const void* data;
00497 size_t data_size;
00498 char status;
00499
00500 microfeed_mutex_lock(feed->mutex);
00501
00502 uid_size = (start_uid ? strlen(start_uid) + 1 : 0);
00503 for (iterator = microfeed_database_iterate(feed->statuses_database, start_uid, uid_size, 0);
00504 (microfeed_database_iterator_get(iterator, &key, &key_size, &data, &data_size)) && (!end_uid || strcmp ((const char*)key, end_uid) <= 0);
00505 microfeed_database_iterator_next(iterator)) {
00506 status = *((char*)data);
00507 if (status & (char)status_to_unset) {
00508 status &= (char)(~status_to_unset);
00509 microfeed_publisher_send_status_changed_signal(feed->publisher, NULL, feed->uri, (const char*)key, status);
00510 if (status) {
00511 microfeed_database_replace_data(feed->statuses_database, key, key_size, &status, sizeof(char));
00512 } else {
00513 microfeed_database_remove_data(feed->statuses_database, key, key_size);
00514 }
00515 }
00516 }
00517 microfeed_database_iterator_free(iterator);
00518
00519 microfeed_mutex_unlock(feed->mutex);
00520 }
00521
00522 void microfeed_feed_add_new_setting(MicrofeedFeed* feed, const char* uid, time_t position, const char* text, const char* unit, const char* type, const char* value) {
00523 MicrofeedItem* item;
00524
00525 item = microfeed_item_new(uid, position);
00526 microfeed_item_set_property(item, "setting.text", text);
00527 microfeed_item_set_property(item, "setting.type", type);
00528 microfeed_item_set_property(item, "setting.unit", unit);
00529 microfeed_item_set_property(item, "setting.value", value);
00530 microfeed_feed_replace_item(feed, item);
00531 microfeed_item_free(item);
00532 }
00533
00534 void microfeed_feed_send_item_data(MicrofeedFeed* feed, const char* uid, const char* bus_name) {
00535 void* key;
00536 size_t key_size;
00537 void* data;
00538 size_t data_size;
00539 SendItemDataData* sid_data;
00540 const char* existing_bus_name;
00541
00542 microfeed_mutex_lock(feed->mutex);
00543
00544 if (!feed->item_data_database) {
00545 microfeed_publisher_send_error_signal(feed->publisher, bus_name, MICROFEED_ERROR_NO_ITEM_DATA, feed->uri, uid, "Feed does not support item data");
00546 } else if (!microfeed_database_index_get_data(feed->database_index, uid, strlen(uid) + 1, &key, &key_size, &data, &data_size)) {
00547 microfeed_publisher_send_error_signal(feed->publisher, bus_name, MICROFEED_ERROR_NO_SUCH_ITEM, feed->uri, uid, "Item does not exist");
00548 } else {
00549 if (microfeed_database_get_data(feed->item_data_database, uid, strlen(uid) + 1, &data, &data_size) && data_size > sizeof(uint64_t)) {
00550 microfeed_publisher_send_item_data_signal(feed->publisher, bus_name, feed->uri, uid, data + sizeof(uint64_t), data_size - sizeof(uint64_t));
00551 free(data);
00552 } else {
00553 if (!(sid_data = microfeed_store_get(feed->send_item_data_datas, uid, SendItemDataData))) {
00554 sid_data = microfeed_memory_allocate(SendItemDataData);
00555 sid_data->uid = strdup(uid);
00556 sid_data->feed = feed;
00557 sid_data->bus_names = microfeed_store_new_sorted(microfeed_store_compare_keys_direct, microfeed_store_get_key_direct);
00558 microfeed_store_insert(feed->send_item_data_datas, sid_data);
00559
00560 microfeed_publisher_queue_thread(feed->publisher, send_item_data_thread, sid_data);
00561 }
00562 if (!(existing_bus_name = microfeed_store_get(sid_data->bus_names, bus_name, const char))) {
00563 microfeed_store_insert(sid_data->bus_names, strdup(bus_name));
00564 }
00565 }
00566 }
00567
00568 microfeed_mutex_unlock(feed->mutex);
00569 }
00570
00571 void microfeed_feed_ref_item_data(MicrofeedFeed* feed, const char* uid) {
00572 size_t uid_size;
00573 uint64_t reference_count;
00574 size_t size;
00575 MicrofeedItem* item;
00576 uint64_t timestamp;
00577 void* key;
00578 size_t key_size;
00579 const void* data;
00580 size_t data_size;
00581 char status;
00582
00583 microfeed_mutex_lock(feed->mutex);
00584
00585 if (feed->item_data_database) {
00586 uid_size = strlen(uid) + 1;
00587 size = sizeof(uint64_t);
00588 if (microfeed_database_get_data_partial(feed->item_data_database, uid, uid_size, &reference_count, &size, 0) && size == sizeof(uint64_t)) {
00589 reference_count++;
00590 microfeed_database_replace_data_partial(feed->item_data_database, uid, uid_size, &reference_count, size, 0);
00591 } else {
00592 reference_count = 1;
00593 microfeed_database_replace_data(feed->item_data_database, uid, uid_size, &reference_count, size);
00594 item = microfeed_item_new(uid, time(NULL));
00595 timestamp = (uint64_t)microfeed_item_get_timestamp(item);
00596 key_size = sizeof(uint64_t) + uid_size;
00597 key = (char*)malloc(key_size);
00598 *((uint64_t*)key) = timestamp;
00599 memcpy(key + sizeof(uint64_t), uid, uid_size);
00600 microfeed_item_marshal_properties(item, &data, &data_size);
00601 microfeed_publisher_send_item_signal(feed->publisher, NULL, "ItemAdded", feed->uri, item);
00602 microfeed_database_replace_data(feed->database, key, key_size, data, data_size);
00603 microfeed_database_replace_data(feed->statuses_database, uid, uid_size, &status, sizeof(char));
00604 }
00605 }
00606
00607 microfeed_mutex_unlock(feed->mutex);
00608 }
00609
00610 void microfeed_feed_unref_item_data(MicrofeedFeed* feed, const char* uid) {
00611 size_t uid_size;
00612 uint64_t reference_count;
00613 size_t size;
00614
00615 microfeed_mutex_lock(feed->mutex);
00616
00617 if (feed->item_data_database) {
00618 uid_size = strlen(uid) + 1;
00619 size = sizeof(uint64_t);
00620 if (microfeed_database_get_data_partial(feed->item_data_database, uid, uid_size, &reference_count, &size, 0) && size == sizeof(uint64_t)) {
00621 reference_count--;
00622 if (reference_count == 0) {
00623 microfeed_database_index_remove_data(feed->database_index, uid, uid_size);
00624 microfeed_database_remove_data(feed->statuses_database, uid, uid_size);
00625 microfeed_database_remove_data(feed->item_data_database, uid, uid_size);
00626 microfeed_publisher_send_item_uid_signal(feed->publisher, NULL, "ItemRemoved", feed->uri, uid);
00627 } else {
00628 microfeed_database_replace_data_partial(feed->item_data_database, uid, uid_size, &reference_count, size, 0);
00629 }
00630 }
00631 }
00632
00633 microfeed_mutex_unlock(feed->mutex);
00634 }
00635
00636 void microfeed_feed_iterator_free(MicrofeedFeedIterator* iterator) {
00637 if (iterator->next) {
00638 iterator->next->previous = iterator->previous;
00639 }
00640 if (iterator->previous) {
00641 iterator->previous->next = iterator->next;
00642 } else if (iterator->feed) {
00643 iterator->feed->iterators = iterator->next;
00644 }
00645
00646 iterator->feed = NULL;
00647 microfeed_database_iterator_free(iterator->database_iterator);
00648 microfeed_memory_free(iterator);
00649 }
00650
00651 MicrofeedFeed* microfeed_feed_iterator_get_feed(MicrofeedFeedIterator* iterator) {
00652
00653 return iterator->feed;
00654 }
00655
00656 MicrofeedItem* microfeed_feed_iterator_get_item(MicrofeedFeedIterator* iterator) {
00657 const void* key;
00658 size_t key_size;
00659 const void* data;
00660 size_t data_size;
00661 uint64_t timestamp;
00662 MicrofeedItem* item;
00663
00664 microfeed_mutex_lock(iterator->feed->mutex);
00665
00666 if (!microfeed_database_iterator_get(iterator->database_iterator, &key, &key_size, &data, &data_size)) {
00667 item = NULL;
00668 } else {
00669 timestamp = *((uint64_t*)key);
00670 item = microfeed_item_new(key + sizeof(uint64_t), (time_t)timestamp);
00671 microfeed_item_demarshal_properties(item, data, data_size);
00672 }
00673
00674 microfeed_mutex_unlock(iterator->feed->mutex);
00675
00676 return item;
00677 }
00678
00679 void microfeed_feed_iterator_next(MicrofeedFeedIterator* iterator) {
00680 microfeed_database_iterator_next(iterator->database_iterator);
00681 }
00682
00683 int microfeed_feed_iterator_jump_and_remove_previous_items(MicrofeedFeedIterator* iterator, const char* uid) {
00684 int retval = 0;
00685 size_t uid_size;
00686 void* start_key;
00687 size_t start_key_size;
00688 void* end_key;
00689 size_t end_key_size;
00690 void* jump_key;
00691 size_t jump_key_size;
00692 const void* key;
00693 size_t key_size;
00694 void* data;
00695 const void* const_data;
00696 size_t data_size;
00697
00698 microfeed_mutex_lock(iterator->feed->mutex);
00699
00700 uid_size = strlen(uid) + 1;
00701 if (microfeed_database_index_get_data(iterator->feed->database_index, uid, uid_size, &jump_key, &jump_key_size, &data, &data_size)) {
00702 retval = 1;
00703 free(data);
00704 if (microfeed_database_iterator_get(iterator->database_iterator, &key, &key_size, &const_data, &data_size) && (key_size - sizeof(uint64_t) != uid_size || memcmp(key + sizeof(uint64_t), uid, uid_size))) {
00705 start_key = malloc(key_size);
00706 memcpy(start_key, key, key_size);
00707 start_key_size = key_size;
00708 end_key = malloc(key_size);
00709 memcpy(end_key, key, key_size);
00710 end_key_size = key_size;
00711 while (microfeed_database_iterator_get(iterator->database_iterator, &key, &key_size, &const_data, &data_size) && (key_size != jump_key_size || memcmp(key, jump_key, jump_key_size))) {
00712 end_key = realloc(end_key, key_size);
00713 memcpy(end_key, key, key_size);
00714 end_key_size = key_size;
00715 microfeed_publisher_send_item_uid_signal(iterator->feed->publisher, NULL, "ItemRemoved", iterator->feed->uri, key + sizeof(uint64_t));
00716 microfeed_database_iterator_next(iterator->database_iterator);
00717 }
00718 free(jump_key);
00719 if (iterator->backwards) {
00720 if (iterator->timeline) {
00721 microfeed_database_remove_data_range(iterator->feed->database, end_key, end_key_size, start_key, start_key_size);
00722 } else {
00723 microfeed_database_index_remove_data_range(iterator->feed->database_index, end_key + sizeof(uint64_t), end_key_size - sizeof(uint64_t), start_key + sizeof(uint64_t), start_key_size - sizeof(uint64_t));
00724 }
00725 microfeed_database_remove_data_range(iterator->feed->statuses_database, end_key + sizeof(uint64_t), end_key_size - sizeof(uint64_t), start_key + sizeof(uint64_t), start_key_size - sizeof(uint64_t));
00726 } else {
00727 if (iterator->timeline) {
00728 microfeed_database_remove_data_range(iterator->feed->database, start_key, start_key_size, end_key, end_key_size);
00729 } else {
00730 microfeed_database_index_remove_data_range(iterator->feed->database_index, start_key + sizeof(uint64_t), start_key_size - sizeof(uint64_t), end_key + sizeof(uint64_t), end_key_size - sizeof(uint64_t));
00731 }
00732 microfeed_database_remove_data_range(iterator->feed->statuses_database, start_key + sizeof(uint64_t), start_key_size - sizeof(uint64_t), end_key + sizeof(uint64_t), end_key_size - sizeof(uint64_t));
00733 }
00734 free(start_key);
00735 free(end_key);
00736 }
00737 }
00738
00739 microfeed_mutex_unlock(iterator->feed->mutex);
00740
00741 return retval;
00742 }
00743
00744 void microfeed_feed_call_modify_item_callback(MicrofeedFeed* feed, MicrofeedItem* existing_item, MicrofeedItem* new_item) {
00745 ModifyItemData* data;
00746
00747 data = microfeed_memory_allocate(ModifyItemData);
00748 data->feed = feed;
00749 data->existing_item = microfeed_item_duplicate(existing_item);
00750 data->new_item = microfeed_item_duplicate(new_item);
00751
00752 microfeed_mutex_lock(feed->mutex);
00753
00754 if (feed->callbacks.modify_item) {
00755 feed->reference_count++;
00756 microfeed_publisher_queue_thread(feed->publisher, modify_item_thread, data);
00757 } else {
00758
00759 }
00760
00761 microfeed_mutex_unlock(feed->mutex);
00762 }
00763
00764 static void index_function(void* key, const size_t key_size, void* data, const size_t data_size, void** index_key, size_t* index_key_size) {
00765 *index_key = key + sizeof(uint64_t);
00766 *index_key_size = key_size - sizeof(uint64_t);
00767 }
00768
00769 static int compare_function(const void* key1, const size_t key1_size, const void* key2, const size_t key2_size) {
00770 int retvalue = 0;
00771
00772 if (key1_size > sizeof(uint64_t) && key2_size > sizeof(int64_t)) {
00773 if (!(retvalue = *((uint64_t*)key1) - *((uint64_t*)key2))) {
00774 retvalue = strcmp(key1 + sizeof(uint64_t), key2 + sizeof(uint64_t));
00775 }
00776 }
00777
00778 return retvalue;
00779 }
00780
00781 static void* update_thread_periodical(void* data) {
00782 MicrofeedFeed* feed;
00783 MicrofeedError* error;
00784
00785 feed = (MicrofeedFeed*)data;
00786 error = feed->callbacks.update(feed, 0, feed->user_data);
00787
00788 microfeed_mutex_lock(feed->mutex);
00789
00790 if (error) {
00791 microfeed_publisher_send_error_signal(feed->publisher, NULL, microfeed_error_get_name(error), feed->uri, NULL, microfeed_error_get_message(error));
00792 microfeed_error_free(error);
00793 } else {
00794 remove_old_items(feed);
00795 }
00796 microfeed_publisher_send_feed_signal(feed->publisher, NULL, "FeedUpdateEnded", feed->uri);
00797 feed->updating = 0;
00798 feed->reference_count--;
00799 if (feed->reference_count == 0) {
00800 microfeed_feed_free(feed);
00801 } else {
00802
00803 microfeed_mutex_unlock(feed->mutex);
00804 }
00805
00806 return NULL;
00807 }
00808
00809 static void* update_thread_user_initiated(void* data) {
00810 MicrofeedFeed* feed;
00811 MicrofeedError* error;
00812
00813 feed = (MicrofeedFeed*)data;
00814 error = feed->callbacks.update(feed, 1, feed->user_data);
00815
00816 microfeed_mutex_lock(feed->mutex);
00817
00818 if (error) {
00819 microfeed_publisher_send_error_signal(feed->publisher, NULL, microfeed_error_get_name(error), feed->uri, NULL, microfeed_error_get_message(error));
00820 microfeed_error_free(error);
00821 } else {
00822 remove_old_items(feed);
00823 }
00824 microfeed_publisher_send_feed_signal(feed->publisher, NULL, "FeedUpdateEnded", feed->uri);
00825 feed->updating = 0;
00826 feed->reference_count--;
00827 if (feed->reference_count == 0) {
00828 microfeed_feed_free(feed);
00829 } else {
00830
00831 microfeed_mutex_unlock(feed->mutex);
00832 }
00833
00834 return NULL;
00835 }
00836
00837 static void* republish_thread(void* user_data) {
00838 RepublishingData* data;
00839 unsigned int count;
00840 MicrofeedDatabaseIterator* iterator;
00841 const void* key;
00842 size_t key_size;
00843 const void* item_data;
00844 size_t item_data_size;
00845 uint64_t timestamp;
00846 MicrofeedItem* item;
00847 void* status_data;
00848 size_t status_data_size;
00849 char status;
00850
00851
00852 data = (RepublishingData*)user_data;
00853
00854 microfeed_mutex_lock(data->feed->mutex);
00855
00856 microfeed_publisher_send_feed_signal(data->feed->publisher, data->bus_name, "FeedRepublishingStarted", data->feed->uri);
00857
00858 count = 0;
00859 for (iterator = microfeed_database_iterate(data->feed->database, data->end_uid, (data->end_uid ? strlen(data->end_uid) + 1 : 0), 1);
00860 microfeed_database_iterator_get(iterator, &key, &key_size, &item_data, &item_data_size);
00861 microfeed_database_iterator_next(iterator)) {
00862 timestamp = *((uint64_t*)key);
00863 if (microfeed_database_get_data(data->feed->statuses_database, key + sizeof(uint64_t), key_size - sizeof(uint64_t), &status_data, &status_data_size)) {
00864 status = *((char*)status_data);
00865 } else {
00866 status = (char)MICROFEED_ITEM_STATUS_NONE;
00867 }
00868 item = microfeed_item_new_with_status(key + sizeof(uint64_t), (time_t)timestamp, (MicrofeedItemStatus)status);
00869 microfeed_item_demarshal_properties(item, item_data, item_data_size);
00870 microfeed_publisher_send_item_signal(data->feed->publisher, data->bus_name, "ItemRepublished", data->feed->uri, item);
00871 microfeed_item_free(item);
00872 if (data->start_uid && strcmp(data->start_uid, key + sizeof(uint64_t)) <= 0) {
00873 break;
00874 }
00875 if (++count == data->max_count) {
00876 break;
00877 }
00878 }
00879 microfeed_database_iterator_free(iterator);
00880
00881 microfeed_publisher_send_feed_signal(data->feed->publisher, data->bus_name, "FeedRepublishingEnded", data->feed->uri);
00882
00883 microfeed_mutex_unlock(data->feed->mutex);
00884
00885 return NULL;
00886 }
00887
00888 static void* send_item_data_thread(void* data) {
00889 SendItemDataData* sid_data;
00890 MicrofeedError* error;
00891 MicrofeedStoreIterator* iterator;
00892 void* item_data;
00893 size_t item_data_size;
00894 char* bus_name;
00895
00896 sid_data = (SendItemDataData*)data;
00897 error = sid_data->feed->callbacks.download_item_data(sid_data->feed, sid_data->uid, &item_data, &item_data_size, sid_data->feed->user_data);
00898
00899 microfeed_mutex_lock(sid_data->feed->mutex);
00900
00901 if (error) {
00902 for (iterator = microfeed_store_iterate(sid_data->bus_names, NULL);
00903 (bus_name = microfeed_store_iterator_get(iterator, char));
00904 microfeed_store_iterator_next(iterator)) {
00905 microfeed_publisher_send_error_signal(sid_data->feed->publisher, bus_name, microfeed_error_get_name(error), sid_data->feed->uri, NULL, microfeed_error_get_message(error));
00906 free(bus_name);
00907 }
00908 microfeed_store_iterator_free(iterator);
00909 microfeed_error_free(error);
00910 } else {
00911 for (iterator = microfeed_store_iterate(sid_data->bus_names, NULL);
00912 (bus_name = microfeed_store_iterator_get(iterator, char));
00913 microfeed_store_iterator_next(iterator)) {
00914 microfeed_publisher_send_item_data_signal(sid_data->feed->publisher, bus_name, sid_data->feed->uri, sid_data->uid, item_data, item_data_size);
00915 free(bus_name);
00916 }
00917 microfeed_store_iterator_free(iterator);
00918
00919 item_data = realloc(item_data, item_data_size + sizeof(uint64_t));
00920 memmove(item_data + sizeof(uint64_t), item_data, item_data_size);
00921 item_data_size += sizeof(uint64_t);
00922 *((uint64_t*)item_data) = 1;
00923 microfeed_database_replace_data(sid_data->feed->item_data_database, sid_data->uid, strlen(sid_data->uid) + 1, item_data, item_data_size);
00924 free(item_data);
00925 }
00926 microfeed_store_remove(sid_data->feed->send_item_data_datas, sid_data);
00927
00928 microfeed_mutex_unlock(sid_data->feed->mutex);
00929
00930 microfeed_store_free(sid_data->bus_names);
00931 free(sid_data->uid);
00932 microfeed_memory_free(sid_data);
00933
00934 return NULL;
00935 }
00936
00937 static void* modify_item_thread(void* user_data) {
00938 ModifyItemData* data;
00939 MicrofeedError* error;
00940
00941 data = (ModifyItemData*)user_data;
00942 error = data->feed->callbacks.modify_item(data->feed, data->existing_item, data->new_item, data->feed->user_data);
00943
00944 microfeed_mutex_lock(data->feed->mutex);
00945
00946 if (error) {
00947 microfeed_publisher_send_error_signal(data->feed->publisher, NULL, microfeed_error_get_name(error), data->feed->uri, microfeed_item_get_uid((data->existing_item ? data->existing_item : data->new_item)), microfeed_error_get_message(error));
00948 microfeed_error_free(error);
00949 }
00950
00951 microfeed_item_free(data->existing_item);
00952 microfeed_item_free(data->new_item);
00953
00954 microfeed_mutex_unlock(data->feed->mutex);
00955
00956 return NULL;
00957 }
00958
00959 static void remove_old_items(MicrofeedFeed* feed) {
00960 time_t timestamp;
00961 int keep_old_items;
00962
00963 keep_old_items = atoi(microfeed_publisher_get_setting_value(feed->publisher, "keep_old_items", "0"));
00964 timestamp = time(NULL) + 60 * 60 * keep_old_items;
00965
00966
00967
00968 }
00969
00970 static const char* send_item_data_data_get_uid(SendItemDataData* send_item_data_data) {
00971
00972 return send_item_data_data->uid;
00973 }
00974
00975