package Ġno . ve g ves en . saga . modules . gcp . storage Ċ Ċ import Ġarrow . core . Either Ċ import Ġarrow . core . flatMap Ċ import Ġarrow . core . handleError With Ċ import Ġarrow . core . left Ċ import Ġarrow . core . right Ċ import Ġarrow . core . right If NotNull Ċ import Ġcom . google . cloud . http . Http Transport Options Ċ import Ġcom . google . cloud . storage . Blob Ċ import Ġcom . google . cloud . storage . Blob Id Ċ import Ġcom . google . cloud . storage . Blob Info Ċ import Ġcom . google . cloud . storage . Storage Ċ import Ġcom . google . cloud . storage . Storage Exception Ċ import Ġcom . google . cloud . storage . Storage Options Ċ import Ġno . ve g ves en . saga . modules . shared . ContentType Ċ import Ġno . ve g ves en . saga . modules . shared . blob storage . Blob Storage Ċ import Ġno . ve g ves en . saga . modules . shared . blob storage . Blob Storage Browser Ċ import Ġno . ve g ves en . saga . modules . shared . blob storage . Blob Storage Error Ċ import Ġno . ve g ves en . saga . modules . shared . blob storage . File Metadata Ċ import Ġno . ve g ves en . saga . modules . shared . blob storage . G zip De compression Behaviour Ċ import Ġno . ve g ves en . saga . modules . shared . blob storage . Load File Options Ċ import Ġno . ve g ves en . saga . modules . shared . blob storage . Save File Options Ċ import Ġno . ve g ves en . saga . modules . shared . blob storage . Storage Path Ċ import Ġno . ve g ves en . saga . modules . shared . gzip Compress Ċ import Ġno . ve g ves en . saga . modules . shared . gzip De compress Ċ import Ġjava . nio . ByteBuffer Ċ import Ġjava . time . Instant Ċ Ċ /** Ċ TODO : ĠConsider Ġadding Ġstream - oriented Ġmethods , Ċ such Ġthat Ġone Ġdoes Ġnot Ġhave Ġto Ġkeep Ġentire ĠByte Arrays Ġin Ġmemory . Ċ NOTE : ĠTests Ġfor Ġthis Ġclass Ġis Ġin Ġno / ve g ves en / saga / modules / gcp / integration tests / G cp Blob Storage Integration Tests . kt Ċ Ġ*/ Ċ class ĠG cp Blob Storage ( private Ġval Ġstorage : ĠStorage ) Ġ: ĠBlob Storage , ĠBlob Storage Browser Ġ{ ĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġfun Ġcreate ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġconnect Timeout : ĠInt Ġ= Ġ 1 0 0 0 , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġread Timeout : ĠInt Ġ= Ġ 4 0 0 0 ĊĠĠĠĠĠĠĠ Ġ): ĠG cp Blob Storage Ġ= ĠStorage Options . newBuilder () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Transport Options ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠHttp Transport Options . newBuilder () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Connect Timeout ( connect Timeout ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Read Timeout ( read Timeout ). build () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ). build (). service . let (:: G cp Blob Storage ) ĊĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠPRE CONDITION _ FAILED Ġ= Ġ 4 1 2 ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġsave File ( ĊĠĠĠĠĠĠĠ Ġstorage Path : ĠStorage Path , ĊĠĠĠĠĠĠĠ Ġfile Content : ĠByteArray , ĊĠĠĠĠĠĠĠ ĠcontentType : ĠContentType , ĊĠĠĠĠĠĠĠ Ġoptions : ĠSave File Options ĊĠĠĠ Ġ): ĠEither < Throwable , ĠUnit > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcreate Options Ġ= ĠarrayOf ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( options . no Overwrite ) ĠStorage . Blob Target Option . does NotExist () Ġelse Ġnull , ĊĠĠĠĠĠĠĠ Ġ). filter NotNull (). to Typed Array () ĊĊĠĠĠĠĠĠĠ Ġval Ġblob Info Builder Ġ= ĠBlob Info . newBuilder ( storage Path . bucketName , Ġstorage Path . fileName ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. set ContentType ( contentType . value ) ĊĊĠĠĠĠĠĠĠ Ġif Ġ( options . gzip Content ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġblob Info Builder . setContent Encoding (" gzip ") ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġoptions . custom Time ?. also Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġblob Info Builder . set Custom Time ( it . to Epoch Milli ()) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġoptions . custom Metadata ?. also Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġblob Info Builder . set Metadata ( it ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn ĠEither . catch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġstorage . create ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġblob Info Builder . build (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( options . gzip Content ) Ġgzip Compress ( file Content ) Ġelse Ġfile Content , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ* create Options ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġsave File IfNot Existing ( ĊĠĠĠĠĠĠĠ Ġstorage Path : ĠStorage Path , ĊĠĠĠĠĠĠĠ Ġfile Content : ĠByteArray , ĊĠĠĠĠĠĠĠ ĠcontentType : ĠContentType , ĊĠĠĠĠĠĠĠ Ġoptions : ĠSave File Options ĊĠĠĠ Ġ): ĠEither < Throwable , ĠBoolean > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġsave File ( storage Path , Ġfile Content , ĠcontentType , Ġoptions . copy ( no Overwrite Ġ= Ġtrue )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġtrue Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. handleError With Ġ{ Ġex Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( ex ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠStorage Exception Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( ex . code Ġ== ĠPRE CONDITION _ FAILED Ġ&& Ġex . location Ġ== Ġ" If - Match ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse . right () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġex . left () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġex . left () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġ@ todo : Ġtest Ġfor ĠStorage Exception . is Retry able Ġand Ġretry Ġautomatically , Ġor Ġby Ġflag ? ĊĠĠĠĠ Ġ* ĠNote Ġfrom ĠP eder : ĠAt tempted Ġto Ġmake Ġthis Ġmethod Ġstreaming , Ġbut ĠStorage ĠAPI Ġmakes Ġthis Ġdifficult ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġload File ( ĊĠĠĠĠĠĠĠ Ġstorage Path : ĠStorage Path , ĊĠĠĠĠĠĠĠ Ġoptions : ĠLoad File Options ĊĠĠĠ Ġ): ĠEither < Blob Storage Error , ĠByteArray > Ġ= ĊĠĠĠĠĠĠĠ ĠBlob Id . of ( storage Path . bucketName , Ġstorage Path . fileName ). let Ġ{ Ġblob Id Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠEither . catch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstorage . get ( blob Id ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Left Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( val Ġex Ġ= Ġit ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠStorage Exception Ġ-> Ġwhen Ġ( ex . code ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 4 0 4 Ġ-> ĠBlob Storage Error . Blob NotFound ( storage Path , Ġex ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> ĠBlob Storage Error . Blob Exception ( ex . message Ġ?: Ġex . toString (), Ġex ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> ĠBlob Storage Error . Blob Exception ( ex . message Ġ?: Ġex . toString (), Ġex ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ Ġit . right If NotNull Ġ{ ĠBlob Storage Error . Blob NotFound ( storage Path ) Ġ} Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ Ġblob Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEither . catch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbytes Ġ= ĠByteBuffer . allocate ( blob . size . toInt ()). let Ġ{ Ġbuffer Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġblob . reader (). read ( buffer ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbuffer . array () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( options . gzip De compression Behaviour ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠG zip De compression Behaviour . NO Ġ-> Ġbytes ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠG zip De compression Behaviour . YES Ġ-> Ġgzip De compress ( bytes ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠG zip De compression Behaviour . AUTO Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( blob . name . endsWith (". gz ") Ġ|| Ġblob . name . endsWith (". gzip ") Ġ|| Ġblob . content Encoding Ġ== Ġ" gzip ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġgzip De compress ( bytes ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbytes ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. map Left Ġ{ Ġex Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠBlob Storage Error . Blob Exception ( ex . message Ġ?: Ġex . toString (), Ġex ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġrewrite File ( storage Path : ĠStorage Path ): ĠEither < Blob Storage Error , ĠUnit > Ġ= ĊĠĠĠĠĠĠĠ ĠEither . catch And Flatten Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġblob Id Ġ= Ġstorage Path . to Blob Id () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġblob Ġ= Ġstorage . get ( blob Id ) Ġ?: Ġreturn ĠBlob Storage Error . Blob NotFound ( storage Path ). left () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcopy Writer Ġ= Ġblob . copy To ( blob Id ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ(! copy Writer . is Done ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcopy Writer . copy Chunk () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ ĠUnit . right () ĊĠĠĠĠĠĠĠ Ġ}. map Left Ġ{ ĠBlob Storage Error . Blob Exception (" Error Ġwhen Ġre writing Ġfile Ġ$ storage Path ", Ġit ) Ġ} ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġcheck If File Exists ( storage Path : ĠStorage Path ): ĠEither < Throwable , ĠBoolean > Ġ= ĠEither . catch Ġ{ ĊĠĠĠĠĠĠĠ Ġstorage . get ( storage Path . to Blob Id ()) Ġ!= Ġnull ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun ĠStorage Path . to Blob Id (): ĠBlob Id Ġ= ĠBlob Id . of ( bucketName , ĠfileName ) ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġlist Files ( bucket : ĠString ): ĠEither < Throwable , ĠList < File Metadata >> Ġ= ĠEither . catch Ġ{ ĊĠĠĠĠĠĠĠ Ġstorage . list ( bucket ). iterate All (). map (:: blob ToFile Metadata ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun ĠgetFile Metadata ( storage Path : ĠStorage Path ): ĠEither < Blob Storage Error , ĠFile Metadata > Ġ= ĊĠĠĠĠĠĠĠ ĠEither . catch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġstorage [ storage Path . bucketName , Ġstorage Path . fileName ] ĊĠĠĠĠĠĠĠ Ġ}. map Left Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠBlob Storage Error . Blob Exception (" Error Ġgetting ĠBlob ", Ġit ) ĊĠĠĠĠĠĠĠ Ġ}. flatMap Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġit ?. let (:: blob ToFile Metadata ). right If NotNull Ġ{ ĠBlob Storage Error . Blob NotFound ( storage Path ) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġblob ToFile Metadata ( blob : ĠBlob ): ĠFile Metadata Ġ= ĊĠĠĠĠĠĠĠ ĠFile Metadata ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠfileName Ġ= Ġblob . name , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠcontentType Ġ= ĠContentType ( blob . contentType ), ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcustom Time Ġ= Ġblob . custom Time ?. let ( Instant :: of Epoch Milli ), ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontent Encoding Ġ= Ġblob . content Encoding , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcustom Metadata Ġ= Ġblob . metadata ĊĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġcopy File ( from : ĠStorage Path , Ġto : ĠStorage Path ): ĠEither < Blob Storage Error , ĠStorage Path > Ġ= ĊĠĠĠĠĠĠĠ Ġstorage [ from . to Blob Id ()]. right If NotNull Ġ{ ĠBlob Storage Error . Blob NotFound ( from ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ Ġfrom Blob Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEither . catch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfrom Blob . copy To ( to . to Blob Id ()). result . let Ġ{ Ġto Blob Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠStorage Path ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġto Blob . bucket , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġto Blob . name ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. map Left Ġ{ ĠBlob Storage Error . Blob Exception (" Failed Ġto Ġcopy Ġfile Ġ'$ from ' Ġto Ġ'$ to '", Ġit ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġdelete File ( storage Path : ĠStorage Path ): ĠEither < Throwable , ĠBoolean > Ġ= ĠEither . catch Ġ{ ĊĠĠĠĠĠĠĠ Ġstorage . delete ( storage Path . to Blob Id ()) ĊĠĠĠ Ġ} Ċ } Ċ