Example #1
0
ActivityObject.ensureObject = function(obj, callback) {

    var type = obj.objectType,
        Cls,
        id = obj.id,
        url = obj.url,
        tryDiscover = function(obj, cb) {
            Step(
                function() {
                    ActivityObject.discover(obj, this);
                },
                function(err, remote) {
                    if (err) {
                        tryCreate(obj, cb);
                    } else {
                        tryCreate(remote, cb);
                    }
                }
            );
        },
        tryCreate = function(obj, cb) {
            Step(
                function() {
                    Cls.create(obj, this);
                },
                function(err, result) {
                    if (err && err.name == "AlreadyExistsError") {
                        ActivityObject.ensureObject(obj, cb);
                    } else if (err) {
                        cb(err, null);
                    } else {
                        cb(null, result);
                    }
                }
            );
        },
        softGet = function(Cls, id, cb) {
            Step(
                function() {
                    Cls.get(id, this);
                },
                function(err, result) {
                    if (err && err.name == "NoSuchThingError") {
                        cb(null, null);
                    } else if (!err) {
                        cb(null, result);
                    } else {
                        cb(err, null);
                    }
                }
            );
        },
        findOne = function(Cls, criteria, cb) {
            Step(
                function() {
                    Cls.search(criteria, this);
                },
                function(err, results) {
                    if (err) throw err;
                    if (!results || results.length === 0) {
                        cb(null, null);
                    } else {
                        cb(null, results[0]);
                    }
                }
            );
        };

    // Since this is a major entry point, check our arguments

    if (!_.isString(id) && !_.isUndefined(id)) {
        callback(new TypeError("ID is not a string: " + id), null);
        return;
    }

    if (!_.isString(url) && !_.isUndefined(url)) {
        callback(new TypeError("URL is not a string: " + url), null);
        return;
    }

    if (!_.isString(type)) {
        callback(new TypeError("Type is not a string: " + type), null);
        return;
    }

    Cls = ActivityObject.toClass(type);

    Step(
        function() {
            if (_.isString(id)) {
                softGet(Cls, id, this);
            } else if (_.isString(url)) {
                // XXX: we could use other fields here to guide search
                findOne(Cls, {url: url}, this);
            } else {
                // XXX: without a unique identifier, just punt
                this(null, null);
            }
        },
        function(err, result) {
            var delta;
            if (err) throw err;
            if (!result) {
                if (!ActivityObject.isLocal(obj)) {
                    tryDiscover(obj, callback);
                } else {
                    // XXX: Log this; it's unusual
                    tryCreate(obj, callback);
                }
            } else if (!ActivityObject.isLocal(obj) &&
                       !ActivityObject.isReference(obj) &&
                       (ActivityObject.isReference(result) || obj.updated > result.updated)) {
                delta = ActivityObject.delta(result, obj);
                result.update(delta, function(err) {
                    if (err) {
                        callback(err, null);
                    } else {
                        callback(null, result);
                    }
                });
            } else {
                callback(null, result);
            }
        }
    );
};
Example #2
0
ActivityObject.ensureObject = function(obj, callback) {

    var type = obj.objectType,
        Cls,
        id = obj.id,
        url = obj.url,
        getRemoteObject = function(url, cb) {
            var Host = require("./host").Host;

            Step(
                function() {
                    var hostname = urlparse(url).hostname;
                    Host.ensureHost(hostname, this);
                },
                function(err, host) {
                    if (err) throw err;
                    host.getOAuth(this);
                },
                function(err, oa) {
                    if (err) throw err;
                    oa.get(url, null, null, this);
                },
                function(err, body, resp) {
                    var parsed;
                    if (err) throw err;
                    if (resp.statusCode != 200) {
                        throw new Error("Bad status code: " + resp.statusCode);
                    }
                    if (!resp.headers["content-type"] || resp.headers["content-type"].substr(0, 16) != "application/json") {
                        throw new Error("Bad content type: " + resp.headers["content-type"]);
                    }
                    parsed = JSON.parse(body);
                    this(null, parsed);
                },
                cb
            );
        },
        mergeLinks = function(jrd, obj) {
            var feeds = ["followers", "following", "links", "favorites", "likes", "replies", "shares"];
            _.each(jrd.links, function(link) {
                var rel = link.rel;
                if (_.contains(feeds, rel)) {
                    obj[rel] = {url: link.href};
                } else {
                    if (!obj.links) {
                        obj.links = {};
                    }
                    obj.links[rel] = {href: link.href};
                }
            });
        },
        tryDiscover = function(obj, cb) {
            var proto = ActivityObject.protocolOf(obj.id),
                wf;

            if (!_.contains(["http", "https", "acct"], proto) ||
                ActivityObject.isDomainToSkip(ActivityObject.domainOf(obj.id))) {
                tryCreate(obj, cb);
                return;
            }

            wf = require("webfinger");

            Step(
                function() {
                    wf.webfinger(obj.id, this);
                },
                function(err, jrd) {
                    var selfies;
                    if (err) throw err;
                    mergeLinks(jrd, obj);
                    selfies = _.filter(jrd.links, function(link) { return link.rel == "self"; });
                    if (selfies.length > 0) {
                        getRemoteObject(selfies[0].href, this);
                    } else {
                        this(null, obj);
                    }
                },
                function(err, remote) {
                    if (err) {
                        tryCreate(obj, cb);
                    } else {
                        tryCreate(remote, cb);
                    }
                }
            );
        },
        tryCreate = function(obj, cb) {
            Step(
                function() {
                    Cls.create(obj, this);
                },
                function(err, result) {
                    if (err && err.name == "AlreadyExistsError") {
                        ActivityObject.ensureObject(obj, cb);                        
                    } else if (err) {
                        cb(err, null);
                    } else {
                        cb(null, result);
                    }
                }
            );
        },
        softGet = function(Cls, id, cb) {
            Step(
                function() {
                    Cls.get(id, this);
                },
                function(err, result) {
                    if (err && err.name == "NoSuchThingError") {
                        cb(null, null);
                    } else if (!err) {
                        cb(null, result);
                    } else {
                        cb(err, null);
                    }
                }
            );
        },
        findOne = function(Cls, criteria, cb) {
            Step(
                function() {
                    Cls.search(criteria, this);
                },
                function(err, results) {
                    if (err) throw err;
                    if (!results || results.length == 0) {
                        cb(null, null);
                    } else {
                        cb(null, results[0]);
                    }
                }
            );
        };
    
    // Since this is a major entry point, check our arguments

    if (!_.isString(id) && !_.isUndefined(id)) {
        callback(new TypeError("ID is not a string: " + id), null);
        return;
    }

    if (!_.isString(url) && !_.isUndefined(url)) {
        callback(new TypeError("URL is not a string: " + url), null);
        return;
    }

    if (!_.isString(type)) {
        callback(new TypeError("Type is not a string: " + type), null);
        return;
    }

    Cls = ActivityObject.toClass(type);

    Step(
        function() {
            if (_.isString(id)) {
                softGet(Cls, id, this);
            } else if (_.isString(url)) {
                // XXX: we could use other fields here to guide search
                findOne(Cls, {url: url}, this);
            } else {
                // XXX: without a unique identifier, just punt
                this(null, null);
            }
        },
        function(err, result) {
            var delta;
            if (err) throw err;
            if (!result) {
                if (!ActivityObject.isLocal(obj)) {
                    tryDiscover(obj, callback);
                } else {
                    // XXX: Log this; it's unusual
                    tryCreate(obj, callback);
                }
            } else if (!ActivityObject.isLocal(obj) &&
                       !ActivityObject.isReference(obj) &&
                       (ActivityObject.isReference(result) || obj.updated > result.updated)) {
                delta = ActivityObject.delta(result, obj);
                result.update(delta, function(err) {
                    if (err) {
                        callback(err, null);
                    } else {
                        callback(null, result);
                    }
                });
            } else {
                callback(null, result);
            }
        }
    );
};