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)
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
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)
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)
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)
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))
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)