106106from gevent .pool import Pool as GPool
107107from cachetools import LRUCache
108108from steam import webapi
109- from steam .exceptions import SteamError
109+ from steam .exceptions import SteamError , ManifestError
110110from steam .core .msg import MsgProto
111111from steam .enums import EResult , EType
112112from steam .enums .emsg import EMsg
@@ -628,7 +628,48 @@ def get_chunk(self, app_id, depot_id, chunk_id):
628628
629629 return self ._chunk_cache [(depot_id , chunk_id )]
630630
631- def get_manifest (self , app_id , depot_id , manifest_gid , decrypt = True ):
631+ def get_manifest_request_code (self , app_id , depot_id , manifest_gid , branch = 'public' , branch_password_hash = None ):
632+ """Get manifest request code for authenticating manifest download
633+
634+ :param app_id: App ID
635+ :type app_id: int
636+ :param depot_id: Depot ID
637+ :type depot_id: int
638+ :param manifest_gid: Manifest gid
639+ :type manifest_gid: int
640+ :param branch: (optional) branch name
641+ :type branch: str
642+ :param branch_password_hash: (optional) branch password hash
643+ :type branch_password_hash: str
644+ :returns: manifest request code
645+ :rtype: int
646+ """
647+
648+ body = {
649+ "app_id" : int (app_id ),
650+ "depot_id" : int (depot_id ),
651+ "manifest_id" : int (manifest_gid ),
652+ }
653+
654+ if branch and branch .lower () != 'public' :
655+ body ['app_branch' ] = branch
656+
657+ if branch_password_hash :
658+ body ['branch_password_hash' ] = branch_password_hash
659+
660+ resp = self .steam .send_um_and_wait (
661+ 'ContentServerDirectory.GetManifestRequestCode#1' ,
662+ body ,
663+ timeout = 5 ,
664+ )
665+
666+ if resp is None or resp .header .eresult != EResult .OK :
667+ raise SteamError ("Failed to get manifest code for %s, %s, %s" % (app_id , depot_id , manifest_gid ),
668+ EResult .Timeout if resp is None else EResult (resp .header .eresult ))
669+
670+ return resp .body .manifest_request_code
671+
672+ def get_manifest (self , app_id , depot_id , manifest_gid , decrypt = True , manifest_request_code = 0 ):
632673 """Download a manifest file
633674
634675 :param app_id: App ID
@@ -639,11 +680,16 @@ def get_manifest(self, app_id, depot_id, manifest_gid, decrypt=True):
639680 :type manifest_gid: int
640681 :param decrypt: Decrypt manifest filenames
641682 :type decrypt: bool
683+ :param manifest_request_code: Manifest request code, authenticates the download
684+ :type manifest_request_code: int
642685 :returns: manifest instance
643686 :rtype: :class:`.CDNDepotManifest`
644687 """
645688 if (app_id , depot_id , manifest_gid ) not in self .manifests :
646- resp = self .cdn_cmd ('depot' , '%s/manifest/%s/5' % (depot_id , manifest_gid ))
689+ if manifest_request_code :
690+ resp = self .cdn_cmd ('depot' , '%s/manifest/%s/5/%s' % (depot_id , manifest_gid , manifest_request_code ))
691+ else :
692+ resp = self .cdn_cmd ('depot' , '%s/manifest/%s/5' % (depot_id , manifest_gid ))
647693
648694 if resp .ok :
649695 manifest = self .DepotManifestClass (self , app_id , resp .content )
@@ -681,6 +727,19 @@ def get_app_depot_info(self, app_id):
681727 self .app_depots [app_id ] = self .steam .get_product_info ([app_id ])['apps' ][app_id ]['depots' ]
682728 return self .app_depots [app_id ]
683729
730+ def has_license_for_depot (self , depot_id ):
731+ """ Check if there is license for depot
732+
733+ :param depot_id: depot ID
734+ :type depot_id: int
735+ :returns: True if we have license
736+ :rtype: bool
737+ """
738+ if depot_id in self .licensed_depot_ids or depot_id in self .licensed_app_ids :
739+ return True
740+ else :
741+ return False
742+
684743 def get_manifests (self , app_id , branch = 'public' , password = None , filter_func = None , decrypt = True ):
685744 """Get a list of CDNDepotManifest for app
686745
@@ -694,7 +753,7 @@ def get_manifests(self, app_id, branch='public', password=None, filter_func=None
694753 Function to filter depots. ``func(depot_id, depot_info)``
695754 :returns: list of :class:`.CDNDepotManifest`
696755 :rtype: :class:`list` [:class:`.CDNDepotManifest`]
697- :raises SteamError: error message
756+ :raises: ManifestError, SteamError
698757 """
699758 depots = self .get_app_depot_info (app_id )
700759
@@ -717,9 +776,24 @@ def get_manifests(self, app_id, branch='public', password=None, filter_func=None
717776 if (app_id , branch ) not in self .beta_passwords :
718777 raise SteamError ("Incorrect password for branch %r" % branch )
719778
720- def async_fetch_manifest (app_id , depot_id , manifest_gid , decrypt , name ):
721- manifest = self .get_manifest (app_id , depot_id , manifest_gid , decrypt )
722- manifest .name = name
779+ def async_fetch_manifest (
780+ app_id , depot_id , manifest_gid , decrypt , depot_name , branch_name , branch_pass
781+ ):
782+ try :
783+ manifest_code = self .get_manifest_request_code (
784+ app_id , depot_id , int (manifest_gid ), branch_name , branch_pass
785+ )
786+ except SteamError as exc :
787+ return ManifestError ("Failed to acquire manifest code" , app_id , depot_id , manifest_gid , exc )
788+
789+ try :
790+ manifest = self .get_manifest (
791+ app_id , depot_id , manifest_gid , decrypt = decrypt , manifest_request_code = manifest_code
792+ )
793+ except Exception as exc :
794+ return ManifestError ("Failed download" , app_id , depot_id , manifest_gid , exc )
795+
796+ manifest .name = depot_name
723797 return manifest
724798
725799 tasks = []
@@ -736,10 +810,8 @@ def async_fetch_manifest(app_id, depot_id, manifest_gid, decrypt, name):
736810 continue
737811
738812 # if we have no license for the depot, no point trying as we won't get depot_key
739- if (decrypt
740- and depot_id not in self .licensed_depot_ids
741- and depot_id not in self .licensed_app_ids ):
742- self ._LOG .debug ("No license for depot %s (%s). Skipping..." ,
813+ if not self .has_license_for_depot (depot_id ):
814+ self ._LOG .debug ("No license for depot %s (%s). Skipped" ,
743815 repr (depot_info .get ('name' , depot_id )),
744816 depot_id ,
745817 )
@@ -764,29 +836,27 @@ def async_fetch_manifest(app_id, depot_id, manifest_gid, decrypt, name):
764836 manifest_gid = depot_info .get ('manifests' , {}).get (branch )
765837
766838 if manifest_gid is not None :
767- tasks .append (self .gpool .spawn (async_fetch_manifest ,
768- app_id ,
769- depot_id ,
770- manifest_gid ,
771- decrypt ,
772- depot_info .get ('name' , depot_id ),
773- ))
839+ tasks .append (
840+ self .gpool .spawn (
841+ async_fetch_manifest ,
842+ app_id ,
843+ depot_id ,
844+ manifest_gid ,
845+ decrypt ,
846+ depot_info .get ('name' , depot_id ),
847+ branch_name = branch ,
848+ branch_pass = None , # TODO: figure out how to pass this correctly
849+ )
850+ )
774851
775852 # collect results
776853 manifests = []
777854
778855 for task in tasks :
779- manifests .append (task .get ())
780- # try:
781- # result = task.get()
782- # except SteamError as exp:
783- # self._LOG.error("Error: %s", exp)
784- # raise
785- # else:
786- # if isinstance(result, list):
787- # manifests.extend(result)
788- # else:
789- # manifests.append(result)
856+ result = task .get ()
857+ if isinstance (result , ManifestError ):
858+ raise result
859+ manifests .append (result )
790860
791861 # load shared depot manifests
792862 for app_id , depot_ids in iteritems (shared_depots ):
@@ -826,7 +896,7 @@ def get_manifest_for_workshop_item(self, item_id):
826896 :type item_id: int
827897 :returns: manifest instance
828898 :rtype: :class:`.CDNDepotManifest`
829- :raises SteamError: error message
899+ :raises: ManifestError, SteamError
830900 """
831901 resp = self .steam .send_um_and_wait ('PublishedFile.GetDetails#1' , {
832902 'publishedfileids' : [item_id ],
@@ -854,7 +924,12 @@ def get_manifest_for_workshop_item(self, item_id):
854924
855925 app_id = ws_app_id = wf .consumer_appid
856926
857- manifest = self .get_manifest (app_id , ws_app_id , wf .hcontent_file )
927+ try :
928+ manifest_code = self .get_manifest_request_code (app_id , ws_app_id , int (wf .hcontent_file ))
929+ manifest = self .get_manifest (app_id , ws_app_id , wf .hcontent_file , manifest_request_code = manifest_code )
930+ except SteamError as exc :
931+ return ManifestError ("Failed to acquire manifest" , app_id , depot_id , manifest_gid , exc )
932+
858933 manifest .name = wf .title
859934 return manifest
860935
0 commit comments