@@ -24,7 +24,20 @@ defmodule RustlerPrecompiled do
24
24
25
25
* `:crate` - The name of Rust crate if different from the `:otp_app`. This is optional.
26
26
27
- * `:base_url` - A valid URL that is used as base path for the NIF file.
27
+ * `:base_url` - Location where to find the NIFs from. This should be one of the following:
28
+
29
+ * A URL to a directory containing the NIFs. The name of the NIF will be appended to it
30
+ and a GET request will be made. Works well with public GitHub releases.
31
+
32
+ * A tuple of `{URL, headers}`. The headers should be a list of key-value pairs.
33
+ This is useful when the NIFs are hosted in a private server.
34
+
35
+ * A tuple of `{module, function}` where the `function` is an atom representing the function
36
+ name in that module. It's expected a function of arity 1, where the NIF file name is given,
37
+ and it should return a URL or a tuple of `{URL, headers}`.
38
+ This should be used for all cases not covered by the above.
39
+ For example when multiple requests have to be made, like when using a private GitHub release
40
+ through the GitHub API, or when the URLs don't resemble a simple directory.
28
41
29
42
* `:version` - The version of precompiled assets (it is part of the NIF filename).
30
43
@@ -262,13 +275,19 @@ defmodule RustlerPrecompiled do
262
275
263
276
@ native_dir "priv/native"
264
277
278
+ @ doc deprecated: "Use available_nifs/1 instead"
279
+ def available_nif_urls ( nif_module ) when is_atom ( nif_module ) do
280
+ available_nifs ( nif_module )
281
+ |> Enum . map ( fn { _lib_name , { url , _headers } } -> url end )
282
+ end
283
+
265
284
@ doc """
266
- Returns URLs for NIFs based on its module name.
285
+ Returns URLs for NIFs based on its module name as a list of tuples: `[{lib_name, {url, headers}}]` .
267
286
268
287
The module name is the one that defined the NIF and this information
269
288
is stored in a metadata file.
270
289
"""
271
- def available_nif_urls ( nif_module ) when is_atom ( nif_module ) do
290
+ def available_nifs ( nif_module ) when is_atom ( nif_module ) do
272
291
nif_module
273
292
|> metadata_file ( )
274
293
|> read_map_from_file ( )
@@ -286,6 +305,17 @@ defmodule RustlerPrecompiled do
286
305
287
306
@ doc false
288
307
def nif_urls_from_metadata ( metadata ) when is_map ( metadata ) do
308
+ case ( nifs_from_metadata ( metadata ) ) do
309
+ { :ok , nifs } ->
310
+ { :ok , Enum . map ( nifs , fn { _lib_name , { url , _headers } } -> url end ) }
311
+
312
+ { :error , wrong_meta } ->
313
+ { :error , wrong_meta }
314
+ end
315
+ end
316
+
317
+ @ doc false
318
+ def nifs_from_metadata ( metadata ) when is_map ( metadata ) do
289
319
case metadata do
290
320
% {
291
321
targets: targets ,
@@ -320,22 +350,26 @@ defmodule RustlerPrecompiled do
320
350
variants = Map . fetch! ( variants , target_triple )
321
351
322
352
for variant <- variants do
323
- tar_gz_file_url (
324
- base_url ,
325
- lib_name_with_ext ( target_triple , lib_name <> "--" <> Atom . to_string ( variant ) )
326
- )
353
+ lib_name = lib_name_with_ext ( target_triple , lib_name <> "--" <> Atom . to_string ( variant ) )
354
+ { lib_name , tar_gz_file_url ( base_url , lib_name ) }
327
355
end
328
356
end
329
357
330
358
defp maybe_variants_tar_gz_urls ( _ , _ , _ , _ ) , do: [ ]
331
359
360
+ @ doc deprecated: "Use current_target_nifs/1 instead"
361
+ def current_target_nif_urls ( nif_module ) when is_atom ( nif_module ) do
362
+ current_target_nifs ( nif_module )
363
+ |> Enum . map ( fn { _lib_name , { url , _headers } } -> url end )
364
+ end
365
+
332
366
@ doc """
333
- Returns the file URLs to be downloaded for current target.
367
+ Returns the file URLs to be downloaded for current target as a list of tuples: `[{lib_name, {url, headers}}]` .
334
368
335
369
It is in the plural because a target may have some variants for it.
336
370
It receives the NIF module.
337
371
"""
338
- def current_target_nif_urls ( nif_module ) when is_atom ( nif_module ) do
372
+ def current_target_nifs ( nif_module ) when is_atom ( nif_module ) do
339
373
metadata =
340
374
nif_module
341
375
|> metadata_file ( )
@@ -362,9 +396,10 @@ defmodule RustlerPrecompiled do
362
396
363
397
defp tar_gz_urls ( base_url , basename , version , nif_version , target_triple , variants ) do
364
398
lib_name = lib_name ( basename , version , nif_version , target_triple )
399
+ lib_name_with_ext = lib_name_with_ext ( target_triple , lib_name )
365
400
366
401
[
367
- tar_gz_file_url ( base_url , lib_name_with_ext ( target_triple , lib_name ) )
402
+ { lib_name_with_ext , tar_gz_file_url ( base_url , lib_name_with_ext ( target_triple , lib_name ) ) }
368
403
| maybe_variants_tar_gz_urls ( variants , base_url , target_triple , lib_name )
369
404
]
370
405
end
@@ -615,7 +650,7 @@ defmodule RustlerPrecompiled do
615
650
616
651
# `cache_base_dir` is a "private" option used only in tests.
617
652
cache_dir = cache_dir ( config . base_cache_dir , "precompiled_nifs" )
618
- cached_tar_gz = Path . join ( cache_dir , " #{ file_name } .tar.gz" )
653
+ cached_tar_gz = Path . join ( cache_dir , file_name )
619
654
620
655
{ :ok ,
621
656
Map . merge ( basic_metadata , % {
@@ -840,21 +875,34 @@ defmodule RustlerPrecompiled do
840
875
"so"
841
876
end
842
877
843
- "#{ lib_name } .#{ ext } "
878
+ "#{ lib_name } .#{ ext } .tar.gz "
844
879
end
845
880
846
- defp tar_gz_file_url ( base_url , file_name ) do
881
+ defp tar_gz_file_url ( { module , function_name } , file_name )
882
+ when is_atom ( module ) and is_atom ( function_name ) do
883
+ apply ( module , function_name , [ file_name ] )
884
+ end
885
+
886
+ defp tar_gz_file_url ( { base_url , request_headers } , file_name ) do
847
887
uri = URI . parse ( base_url )
848
888
849
889
uri =
850
890
Map . update! ( uri , :path , fn path ->
851
- Path . join ( path || "" , " #{ file_name } .tar.gz" )
891
+ Path . join ( path || "" , file_name )
852
892
end )
853
893
854
- to_string ( uri )
894
+ { to_string ( uri ) , request_headers }
855
895
end
856
896
857
- defp download_nif_artifact ( url ) do
897
+ defp tar_gz_file_url ( base_url , file_name ) do
898
+ tar_gz_file_url ( { base_url , [ ] } , file_name )
899
+ end
900
+
901
+ defp download_nif_artifact ( url ) when is_binary ( url ) do
902
+ download_nif_artifact ( { url , [ ] } )
903
+ end
904
+
905
+ defp download_nif_artifact ( { url , request_headers } ) do
858
906
url = String . to_charlist ( url )
859
907
Logger . debug ( "Downloading NIF from #{ url } " )
860
908
@@ -895,7 +943,10 @@ defmodule RustlerPrecompiled do
895
943
896
944
options = [ body_format: :binary ]
897
945
898
- case :httpc . request ( :get , { url , [ ] } , http_options , options ) do
946
+ request_headers =
947
+ Enum . map ( request_headers , fn { k , v } when is_binary ( k ) -> { String . to_charlist ( k ) , v } end )
948
+
949
+ case :httpc . request ( :get , { url , request_headers } , http_options , options ) do
899
950
{ :ok , { { _ , 200 , _ } , _headers , body } } ->
900
951
{ :ok , body }
901
952
@@ -912,16 +963,17 @@ defmodule RustlerPrecompiled do
912
963
attempts = max_retries ( options )
913
964
914
965
download_results =
915
- for url <- urls , do: { url , with_retry ( fn -> download_nif_artifact ( url ) end , attempts ) }
966
+ for { lib_name , url } <- urls ,
967
+ do: { lib_name , with_retry ( fn -> download_nif_artifact ( url ) end , attempts ) }
916
968
917
969
cache_dir = cache_dir ( "precompiled_nifs" )
918
970
:ok = File . mkdir_p ( cache_dir )
919
971
920
972
Enum . flat_map ( download_results , fn result ->
921
- with { :download , { url , download_result } } <- { :download , result } ,
973
+ with { :download , { lib_name , download_result } } <- { :download , result } ,
922
974
{ :download_result , { :ok , body } } <- { :download_result , download_result } ,
923
975
hash <- :crypto . hash ( @ checksum_algo , body ) ,
924
- path <- Path . join ( cache_dir , basename_from_url ( url ) ) ,
976
+ path <- Path . join ( cache_dir , lib_name ) ,
925
977
{ :file , :ok } <- { :file , File . write ( path , body ) } do
926
978
checksum = Base . encode16 ( hash , case: :lower )
927
979
@@ -931,7 +983,7 @@ defmodule RustlerPrecompiled do
931
983
932
984
[
933
985
% {
934
- url: url ,
986
+ lib_name: lib_name ,
935
987
path: path ,
936
988
checksum: checksum ,
937
989
checksum_algo: @ checksum_algo
@@ -985,14 +1037,6 @@ defmodule RustlerPrecompiled do
985
1037
end )
986
1038
end
987
1039
988
- defp basename_from_url ( url ) do
989
- uri = URI . parse ( url )
990
-
991
- uri . path
992
- |> String . split ( "/" )
993
- |> List . last ( )
994
- end
995
-
996
1040
defp read_map_from_file ( file ) do
997
1041
with { :ok , contents } <- File . read ( file ) ,
998
1042
{ % { } = contents , _ } <- Code . eval_string ( contents ) do
0 commit comments