@@ -14,9 +14,10 @@ defmodule RemotePersistentTerm.Fetcher.S3 do
1414 bucket: bucket ,
1515 key: String . t ( ) ,
1616 region: region ,
17- failover_buckets: [ failover_bucket ] | nil
17+ failover_buckets: [ failover_bucket ] | nil ,
18+ version_id: String . t ( ) | nil
1819 }
19- defstruct [ :bucket , :key , :region , :failover_buckets ]
20+ defstruct [ :bucket , :key , :region , :failover_buckets , :version_id ]
2021
2122 @ failover_bucket_schema [
2223 bucket: [
@@ -136,9 +137,9 @@ defmodule RemotePersistentTerm.Fetcher.S3 do
136137 defp list_object_versions ( state ) do
137138 res =
138139 aws_client_request (
139- & ExAws.S3 . get_bucket_object_versions / 2 ,
140+ : get_bucket_object_versions,
140141 state ,
141- prefix: state . key
142+ [ [ prefix: state . key ] ]
142143 )
143144
144145 with { :ok , % { body: % { versions: versions } } } <- res do
@@ -147,7 +148,8 @@ defmodule RemotePersistentTerm.Fetcher.S3 do
147148 end
148149
149150 defp get_object ( state ) do
150- aws_client_request ( & ExAws.S3 . get_object / 2 , state , state . key )
151+ # aws_client_request(&ExAws.S3.get_object/2, state, state.key)
152+ aws_client_request ( :get_object , state , [ state . key , [ version_id: state . version_id ] ] )
151153 end
152154
153155 defp find_latest ( [ _ | _ ] = contents ) do
@@ -166,14 +168,59 @@ defmodule RemotePersistentTerm.Fetcher.S3 do
166168
167169 defp find_latest ( _ ) , do: { :error , :not_found }
168170
171+ @ impl true
172+ def previous_version ( state ) do
173+ Logger . info (
174+ bucket: state . bucket ,
175+ key: state . key ,
176+ message: "About to fetch previous version of object" ,
177+ version_id: state . version_id
178+ )
179+
180+ with { :ok , versions } <- list_object_versions ( state ) ,
181+ { :ok , previous_version } <- find_previous_version ( versions , state . version_id ) do
182+ { :ok , % { state | version_id: previous_version . version_id } }
183+ else
184+ { :error , reason } ->
185+ Logger . error ( % {
186+ bucket: state . bucket ,
187+ key: state . key ,
188+ reason: inspect ( reason ) ,
189+ message: "Failed to get previous version of object"
190+ } )
191+
192+ { :error , reason }
193+ end
194+ end
195+
196+ defp find_previous_version ( versions , current_version_id ) do
197+ versions
198+ |> Enum . sort_by (
199+ fn version ->
200+ { :ok , datetime , _ } = DateTime . from_iso8601 ( version . last_modified )
201+ datetime
202+ end ,
203+ { :desc , DateTime }
204+ )
205+ |> Enum . find ( fn version ->
206+ version . version_id != current_version_id
207+ end )
208+ |> case do
209+ nil -> { :error , :no_previous_version }
210+ version -> { :ok , version }
211+ end
212+ end
213+
214+ defp aws_client_request ( op , state , opts \\ [ ] )
215+
169216 defp aws_client_request ( op , % { failover_buckets: nil } = state , opts ) do
170217 perform_request ( op , state . bucket , state . region , opts )
171218 end
172219
173220 defp aws_client_request (
174221 op ,
175222 % {
176- failover_buckets: [ _ | _ ] = failover_buckets
223+ failover_buckets: [ _ | _ ] = failover_buckets
177224 } = state ,
178225 opts
179226 ) do
@@ -222,8 +269,8 @@ defmodule RemotePersistentTerm.Fetcher.S3 do
222269 end
223270 end
224271
225- defp perform_request ( op , bucket , region , opts ) do
226- op . ( bucket , opts )
272+ defp perform_request ( func , bucket , region , opts ) do
273+ apply ( ExAws.S3 , func , [ bucket | opts ] )
227274 |> client ( ) . request ( region: region )
228275 end
229276
0 commit comments