зеркало из https://github.com/mozilla/snowl.git
more error handling and feedback tweaks: implement "disabled" source state; handle transactionInProgress in sources.persist; ensure statement reset where not; don't refresh busy or dead sources.
This commit is contained in:
Родитель
2c3cb4a1c9
Коммит
b121fad6b1
|
@ -92,6 +92,12 @@
|
|||
}
|
||||
|
||||
/* Error on collection indicator */
|
||||
#sourcesViewTreeChildren::-moz-tree-image(hasError) {
|
||||
#sourcesViewTreeChildren::-moz-tree-image(hasError),
|
||||
#sourcesViewTreeChildren::-moz-tree-image(isDisabled) {
|
||||
list-style-image: url("chrome://snowl/content/icons/exclamation.png");
|
||||
}
|
||||
|
||||
/* Source is paused/disabled */
|
||||
#sourcesViewTreeChildren::-moz-tree-cell-text(isDisabled) {
|
||||
color: GrayText;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -60,11 +60,11 @@ let SubscriptionListener = {
|
|||
let identity = source.name;
|
||||
|
||||
switch(topic) {
|
||||
case "snowl:subscribe:connect:start":
|
||||
case "snowl:refresh:connect:start":
|
||||
code = "active";
|
||||
message = this.stringBundle.getString("messageConnecting");
|
||||
break;
|
||||
case "snowl:subscribe:connect:end":
|
||||
case "snowl:refresh:connect:end":
|
||||
if (data.split(":")[0] == "duplicate") {
|
||||
this.duplicate(data);
|
||||
}
|
||||
|
@ -74,6 +74,11 @@ let SubscriptionListener = {
|
|||
else if (data == "logindata") {
|
||||
this.logindata(data);
|
||||
}
|
||||
else if (data.split(":", 1)[0] == "error" &&
|
||||
source.attributes["statusCode"] == "db:transactionInProgress") {
|
||||
code = "error";
|
||||
message = this.stringBundle.getString("messageDbBusy");
|
||||
}
|
||||
else if (data.split(":", 1)[0] == "error") {
|
||||
code = "error";
|
||||
errorMsg = data.split("error:")[1];
|
||||
|
@ -92,14 +97,11 @@ let SubscriptionListener = {
|
|||
message = this.stringBundle.getString("messageConnected");
|
||||
}
|
||||
break;
|
||||
case "snowl:subscribe:get:start":
|
||||
case "snowl:refresh:get:start":
|
||||
code = "active";
|
||||
message = this.stringBundle.getString("messageGettingMessages");
|
||||
break;
|
||||
case "snowl:subscribe:get:progress":
|
||||
return;
|
||||
break;
|
||||
case "snowl:subscribe:get:end":
|
||||
case "snowl:refresh:get:end":
|
||||
code = "complete";
|
||||
message = this.stringBundle.getString("messageSuccess");
|
||||
break;
|
||||
|
@ -183,19 +185,17 @@ let Subscriber = {
|
|||
addObservers: function() {
|
||||
// FIXME: integrate the subscription listener into this object
|
||||
// as individual notification handler functions.
|
||||
Observers.add("snowl:subscribe:connect:start", SubscriptionListener);
|
||||
Observers.add("snowl:subscribe:connect:end", SubscriptionListener);
|
||||
Observers.add("snowl:subscribe:get:start", SubscriptionListener);
|
||||
Observers.add("snowl:subscribe:get:progress", SubscriptionListener);
|
||||
Observers.add("snowl:subscribe:get:end", SubscriptionListener);
|
||||
Observers.add("snowl:refresh:connect:start", SubscriptionListener);
|
||||
Observers.add("snowl:refresh:connect:end", SubscriptionListener);
|
||||
Observers.add("snowl:refresh:get:start", SubscriptionListener);
|
||||
Observers.add("snowl:refresh:get:end", SubscriptionListener);
|
||||
},
|
||||
|
||||
removeObservers: function() {
|
||||
Observers.remove("snowl:subscribe:connect:start", SubscriptionListener);
|
||||
Observers.remove("snowl:subscribe:connect:end", SubscriptionListener);
|
||||
Observers.remove("snowl:subscribe:get:start", SubscriptionListener);
|
||||
Observers.remove("snowl:subscribe:get:progress", SubscriptionListener);
|
||||
Observers.remove("snowl:subscribe:get:end", SubscriptionListener);
|
||||
Observers.remove("snowl:refresh:connect:start", SubscriptionListener);
|
||||
Observers.remove("snowl:refresh:connect:end", SubscriptionListener);
|
||||
Observers.remove("snowl:refresh:get:start", SubscriptionListener);
|
||||
Observers.remove("snowl:refresh:get:end", SubscriptionListener);
|
||||
},
|
||||
|
||||
|
||||
|
@ -305,28 +305,7 @@ let Subscriber = {
|
|||
|
||||
this.account.username = aCredentials.username;
|
||||
|
||||
this.account.refresh(null);
|
||||
|
||||
// If error on connect, do not persist.
|
||||
if (this.account.error) {
|
||||
Observers.notify("snowl:subscribe:connect:end", this.account, "error:" + this.account.lastStatus);
|
||||
this.account = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.account.persist();
|
||||
|
||||
// If error on db, don't show success.
|
||||
if (this.account.error) {
|
||||
Observers.notify("snowl:subscribe:connect:end", this.account, "error:" + this.account.lastStatus);
|
||||
this.account = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.account = null;
|
||||
|
||||
if (aCallback)
|
||||
aCallback();
|
||||
this.doSubscribe();
|
||||
},
|
||||
|
||||
subscribeFeed: function(aName, aMachineURI, aCallback) {
|
||||
|
@ -347,12 +326,16 @@ let Subscriber = {
|
|||
// FIXME: fix the API so I don't have to pass a bunch of null values.
|
||||
this.account = new SnowlFeed(null, aName, aMachineURI, null, null);
|
||||
|
||||
this.doSubscribe();
|
||||
},
|
||||
|
||||
doSubscribe: function() {
|
||||
this.account.refresh(null);
|
||||
|
||||
// If error on connect, or error due to null result.doc (not a feed) despite
|
||||
// a successful connect (filtered bad domain or not found url), do not persist.
|
||||
if (this.account.error) {
|
||||
Observers.notify("snowl:subscribe:connect:end", this.account, "error:" + this.account.lastStatus);
|
||||
Observers.notify("snowl:refresh:connect:end", this.account, "error:" + this.account.lastStatus);
|
||||
this.account = null;
|
||||
return;
|
||||
}
|
||||
|
@ -361,7 +344,7 @@ let Subscriber = {
|
|||
|
||||
// If error on db, don't show success.
|
||||
if (this.account.error) {
|
||||
Observers.notify("snowl:subscribe:connect:end", this.account, "error:" + this.account.lastStatus);
|
||||
Observers.notify("snowl:refresh:connect:end", this.account, "error:" + this.account.lastStatus);
|
||||
this.account = null;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ messageInvalid = The location you entered is not recognizable.
|
|||
messageInvalidLoginData = You have to enter a username and password to subscribe to this message source.
|
||||
messageConnectionError = There was an error connecting to this message source. Please check the location and try again.
|
||||
messagePassword = Your credentials were not accepted. Please check your username and password and try again.
|
||||
messageDbBusy = The Database is temporarily busy. Please try again after all sources have finished refreshing.
|
||||
messageConnected = Connected.
|
||||
messageGettingMessages = Getting messages...
|
||||
messageSuccess = You have successfully subscribed to this message source.
|
||||
|
|
|
@ -920,14 +920,19 @@ let SnowlDatastore = {
|
|||
* @returns {integer} the ID of the newly-created record
|
||||
*/
|
||||
insertMessage: function(aSourceID, aExternalID, aSubject, aAuthorID, aTimestamp, aReceived, aLink) {
|
||||
this._insertMessageStatement.params.sourceID = aSourceID;
|
||||
this._insertMessageStatement.params.externalID = aExternalID;
|
||||
this._insertMessageStatement.params.subject = aSubject;
|
||||
this._insertMessageStatement.params.authorID = aAuthorID;
|
||||
this._insertMessageStatement.params.timestamp = aTimestamp;
|
||||
this._insertMessageStatement.params.received = aReceived;
|
||||
this._insertMessageStatement.params.link = aLink;
|
||||
this._insertMessageStatement.execute();
|
||||
try {
|
||||
this._insertMessageStatement.params.sourceID = aSourceID;
|
||||
this._insertMessageStatement.params.externalID = aExternalID;
|
||||
this._insertMessageStatement.params.subject = aSubject;
|
||||
this._insertMessageStatement.params.authorID = aAuthorID;
|
||||
this._insertMessageStatement.params.timestamp = aTimestamp;
|
||||
this._insertMessageStatement.params.received = aReceived;
|
||||
this._insertMessageStatement.params.link = aLink;
|
||||
this._insertMessageStatement.execute();
|
||||
}
|
||||
finally {
|
||||
this._insertMessageStatement.reset();
|
||||
}
|
||||
|
||||
return this.dbConnection.lastInsertRowID;
|
||||
},
|
||||
|
|
|
@ -46,7 +46,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
Cu.import("resource://gre/modules/ISO8601DateUtils.jsm");
|
||||
|
||||
// modules that are generic
|
||||
Cu.import("resource://snowl/modules/log4moz.js");
|
||||
Cu.import("resource://snowl/modules/Mixins.js");
|
||||
Cu.import("resource://snowl/modules/Observers.js");
|
||||
Cu.import("resource://snowl/modules/request.js");
|
||||
|
@ -90,11 +89,8 @@ SnowlFeed.prototype = {
|
|||
// need to check it to find out what kind of object an instance is.
|
||||
constructor: SnowlFeed,
|
||||
|
||||
// XXX Move this to SnowlSource?
|
||||
get _log() {
|
||||
let logger = Log4Moz.repository.getLogger("Snowl.Feed " + this.name);
|
||||
this.__defineGetter__("_log", function() logger);
|
||||
return this._log;
|
||||
get _logName() {
|
||||
return "Snowl.Feed " + (this.name ? this.name : "<new feed>");
|
||||
},
|
||||
|
||||
// If we prompt the user to authenticate, and the user asks us to remember
|
||||
|
@ -282,8 +278,7 @@ SnowlFeed.prototype = {
|
|||
if (typeof time == "undefined" || time == null)
|
||||
time = new Date();
|
||||
|
||||
// FIXME: remove subscribe from this notification's name.
|
||||
Observers.notify("snowl:subscribe:connect:start", this);
|
||||
Observers.notify("snowl:refresh:connect:start", this);
|
||||
|
||||
let request = new Request({
|
||||
// The feed processor is going to parse the response, so we override
|
||||
|
@ -295,9 +290,9 @@ SnowlFeed.prototype = {
|
|||
});
|
||||
this._log.info("refresh request finished, status: " + request.status);
|
||||
|
||||
// FIXME: remove subscribe from this notification's name.
|
||||
Observers.notify("snowl:subscribe:connect:end", this, request.status);
|
||||
Observers.notify("snowl:refresh:connect:end", this, request.status);
|
||||
|
||||
this.attributes["statusCode"] = request.status;
|
||||
this.lastStatus = request.status + " (" + request.statusText + ")";
|
||||
if (request.status < 200 || request.status > 299 || request.responseText.length == 0) {
|
||||
this._log.trace("refresh request failed");
|
||||
|
@ -312,6 +307,8 @@ SnowlFeed.prototype = {
|
|||
if (this._authInfo)
|
||||
this._saveLogin();
|
||||
|
||||
Observers.notify("snowl:refresh:get:start", this);
|
||||
|
||||
// Parse the response.
|
||||
// Note: this happens synchronously, even though it uses a listener
|
||||
// callback, which makes it look like it happens asynchronously.
|
||||
|
@ -368,11 +365,9 @@ SnowlFeed.prototype = {
|
|||
if (!this.humanURI)
|
||||
this.humanURI = feed.link;
|
||||
|
||||
// FIXME: remove subscribe from this notification's name.
|
||||
Observers.notify("snowl:subscribe:get:start", this);
|
||||
this.messages = this._processFeed(feed, time);
|
||||
// FIXME: remove subscribe from this notification's name.
|
||||
Observers.notify("snowl:subscribe:get:end", this);
|
||||
|
||||
Observers.notify("snowl:refresh:get:end", this);
|
||||
},
|
||||
|
||||
|
||||
|
|
|
@ -331,20 +331,25 @@ SnowlMessage.prototype = {
|
|||
statement.params.received = SnowlDateUtils.jsToJulianDate(this.received);
|
||||
}
|
||||
|
||||
// Set params that are common to both types of queries.
|
||||
statement.params.sourceID = this.source.id;
|
||||
statement.params.externalID = this.externalID;
|
||||
statement.params.subject = this.subject;
|
||||
statement.params.authorID = this.author ? this.author.id : null;
|
||||
statement.params.timestamp = SnowlDateUtils.jsToJulianDate(this.timestamp);
|
||||
statement.params.link = this.link ? this.link.spec : null;
|
||||
// FIXME: persist message.current.
|
||||
//statement.params.current = this.current;
|
||||
statement.params.read = this.read;
|
||||
statement.params.headers = JSON.stringify(this.headers);
|
||||
statement.params.attributes = JSON.stringify(this.attributes);
|
||||
|
||||
statement.execute();
|
||||
try {
|
||||
// Set params that are common to both types of queries.
|
||||
statement.params.sourceID = this.source.id;
|
||||
statement.params.externalID = this.externalID;
|
||||
statement.params.subject = this.subject;
|
||||
statement.params.authorID = this.author ? this.author.id : null;
|
||||
statement.params.timestamp = SnowlDateUtils.jsToJulianDate(this.timestamp);
|
||||
statement.params.link = this.link ? this.link.spec : null;
|
||||
// FIXME: persist message.current.
|
||||
//statement.params.current = this.current;
|
||||
statement.params.read = this.read;
|
||||
statement.params.headers = JSON.stringify(this.headers);
|
||||
statement.params.attributes = JSON.stringify(this.attributes);
|
||||
|
||||
statement.execute();
|
||||
}
|
||||
finally {
|
||||
statement.reset();
|
||||
}
|
||||
|
||||
if (this.id) {
|
||||
// FIXME: update the message parts (content, summary).
|
||||
|
@ -495,33 +500,39 @@ SnowlMessagePart.prototype = {
|
|||
// FIXME: update the existing record as appropriate.
|
||||
}
|
||||
else {
|
||||
this._stmtInsertPart.params.messageID = message.id;
|
||||
this._stmtInsertPart.params.partType = this.partType;
|
||||
this._stmtInsertPart.params.content = this.content;
|
||||
this._stmtInsertPart.params.mediaType = this.mediaType;
|
||||
this._stmtInsertPart.params.baseURI = (this.baseURI ? this.baseURI.spec : null);
|
||||
this._stmtInsertPart.params.languageTag = this.languageTag;
|
||||
this._stmtInsertPart.execute();
|
||||
|
||||
this.id = SnowlDatastore.dbConnection.lastInsertRowID;
|
||||
|
||||
// Insert a plaintext version of the content into the partsText fulltext
|
||||
// table, converting it to plaintext first if necessary (and possible).
|
||||
switch (this.mediaType) {
|
||||
case "text/html":
|
||||
case "application/xhtml+xml":
|
||||
case "text/plain":
|
||||
// Give the fulltext record the same doc ID as the row ID of the parts
|
||||
// record so we can join them together to get the part (and thence the
|
||||
// message) when doing a fulltext search.
|
||||
this._stmtInsertPartText.params.docid = this.id;
|
||||
this._stmtInsertPartText.params.content = this.plainText();
|
||||
this._stmtInsertPartText.execute();
|
||||
break;
|
||||
|
||||
default:
|
||||
// It isn't a type we understand, so don't do anything with it.
|
||||
// XXX If it's text/*, shouldn't we fulltext index it anyway?
|
||||
try {
|
||||
this._stmtInsertPart.params.messageID = message.id;
|
||||
this._stmtInsertPart.params.partType = this.partType;
|
||||
this._stmtInsertPart.params.content = this.content;
|
||||
this._stmtInsertPart.params.mediaType = this.mediaType;
|
||||
this._stmtInsertPart.params.baseURI = (this.baseURI ? this.baseURI.spec : null);
|
||||
this._stmtInsertPart.params.languageTag = this.languageTag;
|
||||
this._stmtInsertPart.execute();
|
||||
|
||||
this.id = SnowlDatastore.dbConnection.lastInsertRowID;
|
||||
|
||||
// Insert a plaintext version of the content into the partsText fulltext
|
||||
// table, converting it to plaintext first if necessary (and possible).
|
||||
switch (this.mediaType) {
|
||||
case "text/html":
|
||||
case "application/xhtml+xml":
|
||||
case "text/plain":
|
||||
// Give the fulltext record the same doc ID as the row ID of the parts
|
||||
// record so we can join them together to get the part (and thence the
|
||||
// message) when doing a fulltext search.
|
||||
this._stmtInsertPartText.params.docid = this.id;
|
||||
this._stmtInsertPartText.params.content = this.plainText();
|
||||
this._stmtInsertPartText.execute();
|
||||
break;
|
||||
|
||||
default:
|
||||
// It isn't a type we understand, so don't do anything with it.
|
||||
// XXX If it's text/*, shouldn't we fulltext index it anyway?
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this._stmtInsertPart.reset();
|
||||
this._stmtInsertPartText.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -285,28 +285,41 @@ let SnowlService = {
|
|||
let now = new Date();
|
||||
let staleSources = [];
|
||||
for each (let source in this.sources)
|
||||
if (now - source.lastRefreshed > source.refreshInterval)
|
||||
if (now - source.lastRefreshed > source.refreshInterval &&
|
||||
!this.sourcesByID[source.id].busy &&
|
||||
source.attributes["refreshStatus"] != "disabled")
|
||||
// Do not autorefresh (as opposed to user initiated refresh) if a source
|
||||
// is permanently disabled (404 error eg); do not refresh busy source.
|
||||
staleSources.push(source);
|
||||
this.refreshAllSources(staleSources);
|
||||
},
|
||||
|
||||
get refreshingCount() {
|
||||
return this._refreshingCount ? this._refreshingCount : this._refreshingCount = 0;
|
||||
},
|
||||
|
||||
set refreshingCount(val) {
|
||||
return this._refreshingCount = val;
|
||||
},
|
||||
|
||||
refreshAllSources: function(sources) {
|
||||
let cachedsource;
|
||||
let allSources = sources ? sources : this.sources;
|
||||
|
||||
// Set busy property, notify observer to invalidate tree.
|
||||
// Set busy property.
|
||||
for each (let source in allSources) {
|
||||
this.sourcesByID[source.id].busy = true;
|
||||
this.sourcesByID[source.id].error = false;
|
||||
cachedsource = this.sourcesByID[source.id];
|
||||
if (cachedsource) {
|
||||
cachedsource.busy = true;
|
||||
cachedsource.error = false;
|
||||
cachedsource.attributes["refreshStatus"] = "active";
|
||||
}
|
||||
this.refreshingCount = ++this.refreshingCount;
|
||||
}
|
||||
|
||||
if (allSources.length > 0) {
|
||||
// TODO: Don't set busy on 'all' until we know when the last one is done
|
||||
// so it can be unset.
|
||||
// this._collectionStatsByCollectionID["all"].busy = true;
|
||||
|
||||
// Invalidate tree to show new state.
|
||||
if (allSources.length > 0)
|
||||
// Invalidate collections tree to show new state.
|
||||
Observers.notify("snowl:messages:completed", "refresh");
|
||||
}
|
||||
|
||||
// We specify the same refresh time when refreshing sources so that all
|
||||
// new messages have the same received time, which makes messages sorted by
|
||||
|
@ -315,10 +328,8 @@ let SnowlService = {
|
|||
// when retrieved in the same refresh (f.e. when the user starts their
|
||||
// browser in the morning after leaving it off overnight).
|
||||
let refreshTime = new Date();
|
||||
for each (let source in allSources) {
|
||||
this._log.info("refreshStaleSources: refreshInterval - "+source.refreshInterval);
|
||||
for each (let source in allSources)
|
||||
this.refreshSourceTimer(source, refreshTime);
|
||||
}
|
||||
},
|
||||
|
||||
refreshSourceTimer: function(aSource, aRefreshTime) {
|
||||
|
@ -328,12 +339,18 @@ this._log.info("refreshStaleSources: refreshInterval - "+source.refreshInterval)
|
|||
aSource.name + " - " + aSource.machineURI.spec);
|
||||
try {
|
||||
aSource.refresh(aRefreshTime);
|
||||
aSource.persist(true);
|
||||
}
|
||||
catch(ex) {
|
||||
aSource.lastStatus = ex;
|
||||
aSource.onRefreshError();
|
||||
}
|
||||
try {
|
||||
aSource.persist(true);
|
||||
}
|
||||
catch(ex) {
|
||||
aSource.lastStatus = ex;
|
||||
aSource.onDbError();
|
||||
}
|
||||
} };
|
||||
|
||||
timer.initWithCallback(callback, 10, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
|
|
|
@ -42,6 +42,7 @@ const Cr = Components.results;
|
|||
const Cu = Components.utils;
|
||||
|
||||
// modules that are generic
|
||||
Cu.import("resource://snowl/modules/log4moz.js");
|
||||
Cu.import("resource://snowl/modules/Observers.js");
|
||||
Cu.import("resource://snowl/modules/Sync.js");
|
||||
Cu.import("resource://snowl/modules/URI.js");
|
||||
|
@ -192,7 +193,13 @@ SnowlSource.prototype = {
|
|||
// specified in order for its non-set value to remain null.
|
||||
this.importance = aImportance || null;
|
||||
this.placeID = aPlaceID;
|
||||
this.attributes = aAttributes;
|
||||
this.attributes = aAttributes || new Object;
|
||||
},
|
||||
|
||||
get _log() {
|
||||
let logger = Log4Moz.repository.getLogger(this._logName);
|
||||
this.__defineGetter__("_log", function() logger);
|
||||
return this._log;
|
||||
},
|
||||
|
||||
// For adding isBusy property to collections tree.
|
||||
|
@ -314,12 +321,35 @@ SnowlSource.prototype = {
|
|||
|
||||
onRefreshError: function() {
|
||||
this.error = true;
|
||||
if (this.attributes["statusCode"] = 404) {
|
||||
this.attributes["refreshStatus"] = "disabled";
|
||||
SnowlService.sourcesByID[this.id].attributes["refreshStatus"] = "disabled";
|
||||
}
|
||||
|
||||
this._log.error("Refresh error: " + this.lastStatus);
|
||||
},
|
||||
|
||||
onDbCompleted: function() {
|
||||
// Database source record updated, set notifications and states.
|
||||
if (this.id) {
|
||||
// Only for existing stored sources; notify refreshes collections tree state.
|
||||
SnowlService.sourcesByID[this.id].error = true;
|
||||
SnowlService.sourcesByID[this.id].busy = false;
|
||||
SnowlService.sourcesByID[this.id].error = this.error;
|
||||
SnowlService.refreshingCount = --SnowlService.refreshingCount;
|
||||
}
|
||||
Observers.notify("snowl:messages:completed", this.id);
|
||||
},
|
||||
|
||||
onDbError: function() {
|
||||
this.error = true;
|
||||
if (this.id) {
|
||||
// Only for existing stored sources; notify refreshes collections tree state.
|
||||
SnowlService.sourcesByID[this.id].busy = false;
|
||||
SnowlService.sourcesByID[this.id].error = this.error;
|
||||
SnowlService.refreshingCount = --SnowlService.refreshingCount;
|
||||
Observers.notify("snowl:messages:completed", this.id);
|
||||
}
|
||||
this._log.error("Refresh error: " + this.lastStatus);
|
||||
this._log.error("Database error: " + this.lastStatus);
|
||||
},
|
||||
|
||||
retrieveMessages: function() {
|
||||
|
@ -362,17 +392,40 @@ SnowlSource.prototype = {
|
|||
" humanURI = :humanURI, " +
|
||||
" username = :username, " +
|
||||
"lastRefreshed = :lastRefreshed, " +
|
||||
" importance = :importance " +
|
||||
"WHERE id = :id"
|
||||
" importance = :importance, " +
|
||||
" attributes = :attributes " +
|
||||
"WHERE id = :id"
|
||||
);
|
||||
}
|
||||
else {
|
||||
statement = SnowlDatastore.createStatement(
|
||||
"INSERT INTO sources ( name, type, machineURI, humanURI, username, lastRefreshed, importance) " +
|
||||
"VALUES (:name, :type, :machineURI, :humanURI, :username, :lastRefreshed, :importance)"
|
||||
"INSERT INTO sources ( name, type, machineURI, humanURI, username, " +
|
||||
" lastRefreshed, importance, attributes) " +
|
||||
"VALUES ( :name, :type, :machineURI, :humanURI, :username, " +
|
||||
" :lastRefreshed, :importance, :attributes)"
|
||||
);
|
||||
}
|
||||
|
||||
// Need to get a transaction lock.
|
||||
if (SnowlDatastore.dbConnection.transactionInProgress) {
|
||||
this.attributes["statusCode"] = "db:transactionInProgress";
|
||||
this.lastStatus = "Database temporarily busy, could not get transaction lock";
|
||||
if (this.id) {
|
||||
// Only for existing stored sources; notify refreshes collections tree state.
|
||||
SnowlService.sourcesByID[this.id].busy = false;
|
||||
SnowlService.sourcesByID[this.id].error = this.error;
|
||||
SnowlService.refreshingCount = --SnowlService.refreshingCount;
|
||||
// Observers.notify("snowl:messages:completed", this.id);
|
||||
}
|
||||
else {
|
||||
// New subscriptions need to return feedback.
|
||||
this.error = true;
|
||||
this._log.info("persist: " + this.lastStatus);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SnowlDatastore.dbConnection.beginTransaction();
|
||||
try {
|
||||
statement.params.name = this.name;
|
||||
|
@ -382,12 +435,15 @@ SnowlSource.prototype = {
|
|||
statement.params.username = this.username;
|
||||
statement.params.lastRefreshed = this.lastRefreshed ? SnowlDateUtils.jsToJulianDate(this.lastRefreshed) : null;
|
||||
statement.params.importance = this.importance;
|
||||
statement.params.attributes = JSON.stringify(this.attributes);
|
||||
if (this.id)
|
||||
statement.params.id = this.id;
|
||||
statement.step();
|
||||
if (!this.id) {
|
||||
// Extract the ID of the source from the newly-created database record.
|
||||
this.id = SnowlDatastore.dbConnection.lastInsertRowID;
|
||||
// New source, bump refreshing count.
|
||||
SnowlService.refreshingCount = ++SnowlService.refreshingCount;
|
||||
|
||||
// Update message authors to include the source ID.
|
||||
// FIXME: make SnowlIdentity records have a source property
|
||||
|
@ -465,18 +521,17 @@ this._log.info("persist placeID:sources.id - " + this.placeID + " : " + this.id)
|
|||
if (messagesChanged)
|
||||
// Invalidate stats cache on completion of refresh with new messages.
|
||||
SnowlService._collectionStatsByCollectionID = null;
|
||||
|
||||
// Notify collections view on completion of refresh.
|
||||
SnowlService.sourcesByID[this.id].busy = false;
|
||||
Observers.notify("snowl:messages:completed", this.id);
|
||||
}
|
||||
|
||||
SnowlDatastore.dbConnection.commitTransaction();
|
||||
|
||||
// Source successfully stored/updated.
|
||||
this.onDbCompleted();
|
||||
}
|
||||
catch(ex) {
|
||||
SnowlDatastore.dbConnection.rollbackTransaction();
|
||||
this.lastStatus = ex;
|
||||
this.onRefreshError();
|
||||
this.onDbError();
|
||||
}
|
||||
finally {
|
||||
statement.reset();
|
||||
|
|
|
@ -46,7 +46,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
Cu.import("resource://gre/modules/ISO8601DateUtils.jsm");
|
||||
|
||||
// modules that are generic
|
||||
Cu.import("resource://snowl/modules/log4moz.js");
|
||||
Cu.import("resource://snowl/modules/Mixins.js");
|
||||
Cu.import("resource://snowl/modules/Observers.js");
|
||||
Cu.import("resource://snowl/modules/request.js");
|
||||
|
@ -142,10 +141,8 @@ SnowlTwitter.prototype = {
|
|||
// need to check it to find out what kind of object an instance is.
|
||||
constructor: SnowlTwitter,
|
||||
|
||||
get _log() {
|
||||
let logger = Log4Moz.repository.getLogger("Snowl.Twitter." + this.username);
|
||||
this.__defineGetter__("_log", function() logger);
|
||||
return this._log;
|
||||
get _logName() {
|
||||
return "Snowl.Twitter." + this.username;
|
||||
},
|
||||
|
||||
|
||||
|
@ -341,7 +338,7 @@ SnowlTwitter.prototype = {
|
|||
time = new Date();
|
||||
// this._log.info("start refresh " + this.username + " at " + time);
|
||||
|
||||
Observers.notify("snowl:subscribe:get:start", this);
|
||||
Observers.notify("snowl:refresh:connect:start", this);
|
||||
|
||||
// URL parameters that modify the return value of the request.
|
||||
let params = [];
|
||||
|
@ -376,9 +373,9 @@ SnowlTwitter.prototype = {
|
|||
requestHeaders: requestHeaders
|
||||
});
|
||||
|
||||
// FIXME: remove subscribe from this notification's name.
|
||||
Observers.notify("snowl:subscribe:connect:end", this, request.status);
|
||||
Observers.notify("snowl:refresh:connect:end", this, request.status);
|
||||
|
||||
this.attributes["statusCode"] = request.status;
|
||||
this.lastStatus = request.status + " (" + request.statusText + ")";
|
||||
if (request.status < 200 || request.status > 299 || request.responseText.length == 0) {
|
||||
this.onRefreshError();
|
||||
|
@ -393,12 +390,14 @@ SnowlTwitter.prototype = {
|
|||
this._authInfo = null;
|
||||
}
|
||||
|
||||
Observers.notify("snowl:refresh:get:start", this);
|
||||
|
||||
let items = JSON.parse(request.responseText);
|
||||
this.messages = this._processItems(items, time);
|
||||
|
||||
this.lastRefreshed = time;
|
||||
|
||||
Observers.notify("snowl:subscribe:get:end", this);
|
||||
Observers.notify("snowl:refresh:get:end", this);
|
||||
},
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче