예제 #1
0
class PowerStrip(Item):
    """
    A simulated collection of power points.  This is where L{IAppliance}
    providers get their power from.

    @ivar grid: A read-only reference to an L{IElectricityGrid} provider.  This
    may be a powerup provided by the site store or a L{NullGrid} if no powerup
    is installed.
    """
    voltage = integer()
    grid = dependency.requiresFromSite(IElectricityGrid, NullGrid, NullGrid)

    def setForUSElectricity(self):
        if not self.voltage:
            self.voltage = 110
        else:
            raise RuntimeError("Oops! power strip already set up")

    def draw(self, watts):
        """
        Draw the given amount of power from this strip's electricity grid.

        @param watts: The number of watts to draw.

        @type watts: L{int}
        """
        return self.grid.draw(watts)
예제 #2
0
class CustomizedPublicPage(item.Item):
    """
    L{CustomizedPublicPage} is what allows logged-in users to see dynamic
    resources present in the site store.  Although static resources (under
    http://your-domain.example.com/static) are available to everyone, any user
    who should be able to see content such as http://yoursite/users/some-user/
    when they are logged in must have this installed.
    """
    implements(ISiteRootPlugin)

    typeName = 'mantissa_public_customized'
    schemaVersion = 2

    installedOn = attributes.reference(doc="""
        The Avatar for which this item will attempt to retrieve a customized
        page.
        """)

    powerupInterfaces = [(ISiteRootPlugin, -257)]

    publicSiteRoot = requiresFromSite(IMantissaSite, lambda ignored: None)

    def produceResource(self, request, segments, webViewer):
        """
        Produce a resource that traverses site-wide content, passing down the
        given webViewer.  This delegates to the site store's
        L{IMantissaSite} adapter, to avoid a conflict with the
        L{ISiteRootPlugin} interface.

        This method will typically be given an L{_AuthenticatedWebViewer}, which
        can build an appropriate resource for an authenticated shell page,
        whereas the site store's L{IWebViewer} adapter would show an anonymous
        page.

        The result of this method will be a L{_CustomizingResource}, to provide
        support for resources which may provide L{ICustomizable}.  Note that
        Mantissa itself no longer implements L{ICustomizable} anywhere, though.
        All application code should phase out inspecting the string passed to
        ICustomizable in favor of getting more structured information from the
        L{IWebViewer}.  However, it has not been deprecated yet because
        the interface which allows application code to easily access the
        L{IWebViewer} from view code has not yet been developed; it is
        forthcoming.

        See ticket #2707 for progress on this.
        """
        mantissaSite = self.publicSiteRoot
        if mantissaSite is not None:
            for resource, domain in userbase.getAccountNames(self.store):
                username = '******' % (resource, domain)
                break
            else:
                username = None
            bottomResource, newSegments = mantissaSite.siteProduceResource(
                request, segments, webViewer)
            return (_CustomizingResource(bottomResource,
                                         username), newSegments)
        return None
예제 #3
0
class PowerPlant(Item):
    """
    This is an item which supplies the grid with power.  It lives in the site
    store.

    @ivar grid: a read-only reference to an L{IElectricityGrid} powerup on the
    site store, or a L{NullGrid} if none is installed.  If this item is present
    in a user store, retrieving this will raise a L{RuntimeError}.
    """

    wattage = integer(default=1000, allowNone=False,
                      doc="""
                      The amount of power the grid will be supplied with.
                      Currently a dummy attribute required by axiom for item
                      definition.
                      """)
    grid = dependency.requiresFromSite(IElectricityGrid, noGrid, NullGrid)
예제 #4
0
class SpecifiedBadDefaults(Item):
    """
    Depends on a power grid, but specifies defaults for that dependency that
    should never be invoked.  This item can't retrieve a grid.

    @ivar grid: Retrieving this attribute should never work.  It should raise
    L{RuntimeError}.
    """
    dummy = integer(doc="""
    Dummy attribute required by axiom for Item class definition.
    """)

    grid = dependency.requiresFromSite(IElectricityGrid, noGrid, noGrid)

    def pump(self):
        """
        Attempting to pump the iron lung by talking to the power grid.
        """
        return self.grid.draw(100)
예제 #5
0
class IronLung(Item):
    """
    This item is super serious business!  It has to draw real power from the
    real power grid; it won't be satisfied with fake power; too risky for its
    life-critical operation.  So it doesn't specify a placeholder default grid.

    @ivar grid: a read-only reference to an L{IElectricityGrid} provider,
    resolved via the site store this L{IronLung} is in.
    """

    wattsPerPump = integer(default=100, allowNone=False,
                           doc="""
                           The number of watts to draw from L{self.grid} when
                           L{IronLung.pump} is called.
                           """)

    grid = dependency.requiresFromSite(IElectricityGrid)

    def pump(self):
        """
        Attempting to pump the iron lung by talking to the power grid.
        """
        return self.grid.draw(self.wattsPerPump)
예제 #6
0
class FeedUpdates(Item, Plugin, AmbientEventObserver):
    """
    Receive notifications for web feed updates.
    """
    classProvides(IPlugin, IEridanusPluginProvider, IAmbientEventObserver)

    dummy = integer()

    superfeedrService = requiresFromSite(ISuperfeedrService)

    formatting = {
        u'title': ['title'],
        u'summary': ['summary'],
        u'content': ['content'],
        u'title_summary': ['title', 'summary'],
        u'title_content': ['title', 'content']
    }

    def formatEntry(self, formatting, entry):
        """
        Format an Superfeedr entry element according to the formatting type.
        """
        parts = [
            getattr(entry, elemName, None) or u'<unknown>'
            for elemName in formatting
        ]
        parts = u' -- '.join(map(str, parts))

        try:
            timestamp = Time.fromISO8601TimeAndDate(str(
                entry.published)).asHumanly(tzinfo=const.timezone)
            timestamp = u' (%s)' % (timestamp, )
        except ValueError:
            timestamp = u''

        return u'%s%s' % (parts, timestamp)

    def itemsReceived(self, sub, items):
        """
        Subscription item delivery callback.
        """
        for item in items:
            text = self.formatEntry(self.formatting[sub.formatting],
                                    item.entry)
            sub.source.notice(u'\002%s\002: %s' % (sub.id, text))

    def getSubscriptions(self, subscriber):
        """
        Get all L{SubscribedFeed} for C{subscriber}.
        """
        return self.store.query(SubscribedFeed,
                                SubscribedFeed.subscriber == subscriber,
                                sort=SubscribedFeed.id.ascending)

    def getSubscription(self, id, subscriber):
        """
        Get the L{SubscribedFeed} for C{id} and C{subscriber}.
        """
        return self.store.findUnique(
            SubscribedFeed,
            AND(SubscribedFeed.id == id,
                SubscribedFeed.subscriber == subscriber),
            default=None)

    def _subscribe(self, source, sub):
        """
        Subscribe a L{SubscribedFeed} and register the source to deliver
        notifications via.
        """
        def receiver(sub):
            def _innerReceiver(url, items):
                self.itemsReceived(sub, items)

            return _innerReceiver

        sub.source = source
        return sub.subscribe(self.superfeedrService, receiver(sub))

    def subscribe(self, source, id, url, formatting):
        """
        Create and subscribe a L{SubscribedFeed} and register the source to
        deliver notifications via.
        """
        sub = self.getSubscription(id, source.channel)
        if sub is not None:
            raise errors.InvalidIdentifier(
                u'A subscription with that identifier already exists')

        formatting = formatting.lower()
        if formatting not in self.formatting:
            raise ValueError(u'"%s" is not a valid format specifier' %
                             (formatting, ))

        sub = SubscribedFeed(store=self.store,
                             id=id,
                             url=url,
                             subscriber=source.channel,
                             formatting=formatting)
        return self._subscribe(source, sub)

    def unsubscribe(self, source, id):
        """
        Unsubscribe a L{SubscribedFeed}.
        """
        sub = self.getSubscription(id, source.channel)
        if sub is None:
            raise errors.InvalidIdentifier(
                u'No subscription with that identifier exists')

        return sub.unsubscribe(self.superfeedrService)

    @usage(u'subscribe <id> <url> <formatting>')
    def cmd_subscribe(self, source, id, url, formatting):
        """
        Subscribe to notifications for a feed.

        The `formatting` argument can be one of: "title", "summary", "content",
        "title_summary" or "title_content", indicating that the notification
        should contain the title, summary, content, title and summary, or title
        and content respectively.
        """
        def subscribed(dummy):
            source.reply(u'Subscribed to "%s" <%s>' % (id, url))

        d = self.subscribe(source, id, url, formatting)
        return d.addCallback(subscribed)

    @usage(u'unsubscribe <id>')
    def cmd_unsubscribe(self, source, id):
        """
        Unsubscribe from notifications for a feed.
        """
        def unsubscribed(dummy):
            source.reply(u'Unsubscribed from "%s"' % (id, ))

        d = self.unsubscribe(source, id)
        return d.addCallback(unsubscribed)

    @usage(u'list')
    def cmd_list(self, source):
        """
        List subscriptions.
        """
        def subs():
            for sub in self.getSubscriptions(source.channel):
                yield u'\002%s\002: <%s>' % (sub.id, sub.url)

        msg = u'; '.join(subs())
        source.reply(msg)

    # IAmbientEventObserver

    def joinedChannel(self, source):
        subs = self.store.query(SubscribedFeed,
                                SubscribedFeed.subscriber == source.channel)
        return gatherResults(map(partial(self._subscribe, source), subs))
예제 #7
0
class MessageQueue(Item):
    """
    A queue of outgoing L{QueuedMessage} objects.
    """
    schemaVersion = 2
    powerupInterfaces = (IMessageRouter, )

    siteRouter = requiresFromSite(IMessageRouter, _createLocalRouter,
                                  _accidentalSiteRouter)

    messageCounter = integer("""
        This counter generates identifiers for outgoing messages.
        """,
                             default=0,
                             allowNone=False)

    def _scheduleMePlease(self):
        """
        This queue needs to have its run() method invoked at some point in the
        future.  Tell the dependent scheduler to schedule it if it isn't
        already pending execution.
        """
        sched = IScheduler(self.store)
        if len(list(sched.scheduledTimes(self))) == 0:
            sched.schedule(self, sched.now())

    def routeMessage(self, sender, target, value, messageID):
        """
        Implement L{IMessageRouter.routeMessage} by locating a shared item
        which provides L{IMessageReceiver}, identified by L{target} in this
        L{MessageQueue}'s L{Store}, as shared to the specified C{sender}, then
        invoke its L{messageReceived} method.  Then, take the results of that
        L{messageReceived} invocation and deliver them as an answer to the
        object specified by L{sender}.

        If any of these steps fail such that no
        L{IMessageReceiver.messageReceived} method may be invoked, generate a
        L{DELIVERY_ERROR} response instead.
        """
        avatarName = sender.localpart + u"@" + sender.domain
        # Look for the sender.
        answer = self.store.findUnique(
            _AlreadyAnswered,
            AND(_AlreadyAnswered.originalSender == sender,
                _AlreadyAnswered.messageID == messageID),
            default=None)
        if answer is None:
            role = getPrimaryRole(self.store, avatarName)
            try:
                receiver = role.getShare(target.shareID)
            except NoSuchShare:
                response = Value(DELIVERY_ERROR, ERROR_NO_SHARE)
            else:
                try:

                    def txn():
                        output = receiver.messageReceived(
                            value, sender, target)
                        if not isinstance(output, Value):
                            raise TypeError("%r returned non-Value %r" %
                                            (receiver, output))
                        return output

                    response = self.store.transact(txn)
                except RevertAndRespond, rar:
                    response = rar.value
                except:
                    log.err(
                        Failure(), "An error occurred during inter-store "
                        "message delivery.")
                    response = Value(DELIVERY_ERROR, ERROR_REMOTE_EXCEPTION)