# Copyright (C) 2006-2012 Mortal Coil Games # See LICENSE for details. """ Class for an asset client interface Handles retrieval and storage of assets. """ from twisted.internet import defer from twisted.internet.defer import inlineCallbacks, returnValue, gatherResults from twisted.application.service import Service from zope.interface import implements from mv3d.net.client import ServiceLoc from mv3d.util.iservice import IAssetClient, IPlayerClient from twisted.python.failure import Failure class AssetService(Service): """ You need to add a docstring here ! """ implements(IAssetClient) def __init__(self): self.assetcache = {} self.downloading = {} self.assetServices = [] def configure(self, nm, cf): """ Configure this client with the config file """ if cf.has_option(nm, "assetServices"): asv = cf.get(nm, "assetServices").split(",") for a in asv: a = a.replace("|", ",") # TODO: hack self.assetServices.append(ServiceLoc(a)) def acquireAssets(self, aids, **kw): """ Takes a list of asset ids to acquire eventually returns a dict of id:asset """ d = [] for a in aids: d.append(self.acquireAsset(a, downloadList=[], **kw)) def gotAssets(_assets): d = [] for a in aids: d.append(self.getAsset(a)) return defer.gatherResults(d) return defer.gatherResults(d).addCallback(gotAssets) @inlineCallbacks def acquireAsset(self, aid, downloadList=None, **kw): """ If we locally have this asset in our cache, call its acquire function and return the result. Else find the asset and do that. """ if downloadList is None: downloadList = [] if self.downloading.has_key(aid): d = defer.Deferred() self.downloading[aid].append(d) asset = yield d returnValue(asset) self.downloading[aid] = [] downloadList.append(aid) try: asset = yield self.getAsset(aid) except: for dfrd in self.downloading[aid]: dfrd.errback(Failure()) del self.downloading[aid] raise try: yield asset.acquireDependencies(downloadList=downloadList, **kw) except: for dfrd in self.downloading[aid]: dfrd.errback(Failure()) del self.downloading[aid] raise if asset.haveAsset(): for dfrd in self.downloading[aid]: dfrd.callback(asset) del self.downloading[aid] returnValue(asset) try: yield asset.acquireAsset(downloadList, **kw) except: for dfrd in self.downloading[aid]: dfrd.errback(Failure()) del self.downloading[aid] raise for dfrd in self.downloading[aid]: dfrd.callback(asset) del self.downloading[aid] returnValue(asset) @inlineCallbacks def getAsset(self, aid): """ Get an asset. If it's in our cache, then return it. Otherwise, search with one of our asset servers. """ assert isinstance(aid, tuple), "AssetID is %s not tuple" % aid assert aid[1] is not None if self.assetcache.has_key(aid): returnValue(self.assetcache[aid]) if not len(self.assetServices): p = self.parent.getLocalService(IPlayerClient) svcs = yield p.getAssetServices() self.assetServices += svcs i = yield self.parent.getOneService(self.assetServices) assert i is not self # infinite loop prevention! a = yield i.getAsset(aid) a.parent = self self.assetcache[a.getID()] = a returnValue(a) def getAssets(self, assetIDs): """ Gets a list of asset ids. """ dfrds = [] for aid in assetIDs: dfrds.append(self.getAsset(aid)) return gatherResults(dfrds) def isLocal(self): """ We are local so return true """ return True