106
106
from gevent .pool import Pool as GPool
107
107
from cachetools import LRUCache
108
108
from steam import webapi
109
- from steam .exceptions import SteamError
109
+ from steam .exceptions import SteamError , ManifestError
110
110
from steam .core .msg import MsgProto
111
111
from steam .enums import EResult , EType
112
112
from steam .enums .emsg import EMsg
@@ -628,7 +628,48 @@ def get_chunk(self, app_id, depot_id, chunk_id):
628
628
629
629
return self ._chunk_cache [(depot_id , chunk_id )]
630
630
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 ):
632
673
"""Download a manifest file
633
674
634
675
:param app_id: App ID
@@ -639,11 +680,16 @@ def get_manifest(self, app_id, depot_id, manifest_gid, decrypt=True):
639
680
:type manifest_gid: int
640
681
:param decrypt: Decrypt manifest filenames
641
682
:type decrypt: bool
683
+ :param manifest_request_code: Manifest request code, authenticates the download
684
+ :type manifest_request_code: int
642
685
:returns: manifest instance
643
686
:rtype: :class:`.CDNDepotManifest`
644
687
"""
645
688
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 ))
647
693
648
694
if resp .ok :
649
695
manifest = self .DepotManifestClass (self , app_id , resp .content )
@@ -681,6 +727,19 @@ def get_app_depot_info(self, app_id):
681
727
self .app_depots [app_id ] = self .steam .get_product_info ([app_id ])['apps' ][app_id ]['depots' ]
682
728
return self .app_depots [app_id ]
683
729
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
+
684
743
def get_manifests (self , app_id , branch = 'public' , password = None , filter_func = None , decrypt = True ):
685
744
"""Get a list of CDNDepotManifest for app
686
745
@@ -694,7 +753,7 @@ def get_manifests(self, app_id, branch='public', password=None, filter_func=None
694
753
Function to filter depots. ``func(depot_id, depot_info)``
695
754
:returns: list of :class:`.CDNDepotManifest`
696
755
:rtype: :class:`list` [:class:`.CDNDepotManifest`]
697
- :raises SteamError: error message
756
+ :raises: ManifestError, SteamError
698
757
"""
699
758
depots = self .get_app_depot_info (app_id )
700
759
@@ -717,9 +776,24 @@ def get_manifests(self, app_id, branch='public', password=None, filter_func=None
717
776
if (app_id , branch ) not in self .beta_passwords :
718
777
raise SteamError ("Incorrect password for branch %r" % branch )
719
778
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
723
797
return manifest
724
798
725
799
tasks = []
@@ -736,10 +810,8 @@ def async_fetch_manifest(app_id, depot_id, manifest_gid, decrypt, name):
736
810
continue
737
811
738
812
# 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" ,
743
815
repr (depot_info .get ('name' , depot_id )),
744
816
depot_id ,
745
817
)
@@ -764,29 +836,27 @@ def async_fetch_manifest(app_id, depot_id, manifest_gid, decrypt, name):
764
836
manifest_gid = depot_info .get ('manifests' , {}).get (branch )
765
837
766
838
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
+ )
774
851
775
852
# collect results
776
853
manifests = []
777
854
778
855
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 )
790
860
791
861
# load shared depot manifests
792
862
for app_id , depot_ids in iteritems (shared_depots ):
@@ -826,7 +896,7 @@ def get_manifest_for_workshop_item(self, item_id):
826
896
:type item_id: int
827
897
:returns: manifest instance
828
898
:rtype: :class:`.CDNDepotManifest`
829
- :raises SteamError: error message
899
+ :raises: ManifestError, SteamError
830
900
"""
831
901
resp = self .steam .send_um_and_wait ('PublishedFile.GetDetails#1' , {
832
902
'publishedfileids' : [item_id ],
@@ -854,7 +924,12 @@ def get_manifest_for_workshop_item(self, item_id):
854
924
855
925
app_id = ws_app_id = wf .consumer_appid
856
926
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
+
858
933
manifest .name = wf .title
859
934
return manifest
860
935
0 commit comments