@@ -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,13 @@ defmodule RustlerPrecompiled do
286
305
287
306
@ doc false
288
307
def nif_urls_from_metadata ( metadata ) when is_map ( metadata ) do
308
+ with { :ok , nifs } <- nifs_from_metadata ( metadata ) do
309
+ { :ok , Enum . map ( nifs , fn { _lib_name , { url , _headers } } -> url end ) }
310
+ end
311
+ end
312
+
313
+ @ doc false
314
+ def nifs_from_metadata ( metadata ) when is_map ( metadata ) do
289
315
case metadata do
290
316
% {
291
317
targets: targets ,
@@ -320,22 +346,27 @@ defmodule RustlerPrecompiled do
320
346
variants = Map . fetch! ( variants , target_triple )
321
347
322
348
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
- )
349
+ lib_name = lib_name_with_ext ( target_triple , lib_name <> "--" <> Atom . to_string ( variant ) )
350
+ { lib_name , tar_gz_file_url ( base_url , lib_name ) }
327
351
end
328
352
end
329
353
330
354
defp maybe_variants_tar_gz_urls ( _ , _ , _ , _ ) , do: [ ]
331
355
356
+ @ doc deprecated: "Use current_target_nifs/1 instead"
357
+ def current_target_nif_urls ( nif_module ) when is_atom ( nif_module ) do
358
+ nif_module
359
+ |> current_target_nifs ( )
360
+ |> Enum . map ( fn { _lib_name , { url , _headers } } -> url end )
361
+ end
362
+
332
363
@ doc """
333
- Returns the file URLs to be downloaded for current target.
364
+ Returns the file URLs to be downloaded for current target as a list of tuples: `[{lib_name, {url, headers}}]` .
334
365
335
366
It is in the plural because a target may have some variants for it.
336
367
It receives the NIF module.
337
368
"""
338
- def current_target_nif_urls ( nif_module ) when is_atom ( nif_module ) do
369
+ def current_target_nifs ( nif_module ) when is_atom ( nif_module ) do
339
370
metadata =
340
371
nif_module
341
372
|> metadata_file ( )
@@ -362,9 +393,10 @@ defmodule RustlerPrecompiled do
362
393
363
394
defp tar_gz_urls ( base_url , basename , version , nif_version , target_triple , variants ) do
364
395
lib_name = lib_name ( basename , version , nif_version , target_triple )
396
+ lib_name_with_ext = lib_name_with_ext ( target_triple , lib_name )
365
397
366
398
[
367
- tar_gz_file_url ( base_url , lib_name_with_ext ( target_triple , lib_name ) )
399
+ { lib_name_with_ext , tar_gz_file_url ( base_url , lib_name_with_ext ( target_triple , lib_name ) ) }
368
400
| maybe_variants_tar_gz_urls ( variants , base_url , target_triple , lib_name )
369
401
]
370
402
end
@@ -616,7 +648,7 @@ defmodule RustlerPrecompiled do
616
648
617
649
# `cache_base_dir` is a "private" option used only in tests.
618
650
cache_dir = cache_dir ( config . base_cache_dir , "precompiled_nifs" )
619
- cached_tar_gz = Path . join ( cache_dir , " #{ file_name } .tar.gz" )
651
+ cached_tar_gz = Path . join ( cache_dir , file_name )
620
652
621
653
{ :ok ,
622
654
Map . merge ( basic_metadata , % {
@@ -841,21 +873,34 @@ defmodule RustlerPrecompiled do
841
873
"so"
842
874
end
843
875
844
- "#{ lib_name } .#{ ext } "
876
+ "#{ lib_name } .#{ ext } .tar.gz "
845
877
end
846
878
847
- defp tar_gz_file_url ( base_url , file_name ) do
879
+ defp tar_gz_file_url ( { module , function_name } , file_name )
880
+ when is_atom ( module ) and is_atom ( function_name ) do
881
+ apply ( module , function_name , [ file_name ] )
882
+ end
883
+
884
+ defp tar_gz_file_url ( { base_url , request_headers } , file_name ) do
848
885
uri = URI . parse ( base_url )
849
886
850
887
uri =
851
888
Map . update! ( uri , :path , fn path ->
852
- Path . join ( path || "" , " #{ file_name } .tar.gz" )
889
+ Path . join ( path || "" , file_name )
853
890
end )
854
891
855
- to_string ( uri )
892
+ { to_string ( uri ) , request_headers }
893
+ end
894
+
895
+ defp tar_gz_file_url ( base_url , file_name ) do
896
+ tar_gz_file_url ( { base_url , [ ] } , file_name )
897
+ end
898
+
899
+ defp download_nif_artifact ( url ) when is_binary ( url ) do
900
+ download_nif_artifact ( { url , [ ] } )
856
901
end
857
902
858
- defp download_nif_artifact ( url ) do
903
+ defp download_nif_artifact ( { url , request_headers } ) do
859
904
url = String . to_charlist ( url )
860
905
Logger . debug ( "Downloading NIF from #{ url } " )
861
906
@@ -896,7 +941,10 @@ defmodule RustlerPrecompiled do
896
941
897
942
options = [ body_format: :binary ]
898
943
899
- case :httpc . request ( :get , { url , [ ] } , http_options , options ) do
944
+ request_headers =
945
+ Enum . map ( request_headers , fn { k , v } when is_binary ( k ) -> { String . to_charlist ( k ) , v } end )
946
+
947
+ case :httpc . request ( :get , { url , request_headers } , http_options , options ) do
900
948
{ :ok , { { _ , 200 , _ } , _headers , body } } ->
901
949
{ :ok , body }
902
950
@@ -913,16 +961,17 @@ defmodule RustlerPrecompiled do
913
961
attempts = max_retries ( options )
914
962
915
963
download_results =
916
- for url <- urls , do: { url , with_retry ( fn -> download_nif_artifact ( url ) end , attempts ) }
964
+ for { lib_name , url } <- urls ,
965
+ do: { lib_name , with_retry ( fn -> download_nif_artifact ( url ) end , attempts ) }
917
966
918
967
cache_dir = cache_dir ( "precompiled_nifs" )
919
968
:ok = File . mkdir_p ( cache_dir )
920
969
921
970
Enum . flat_map ( download_results , fn result ->
922
- with { :download , { url , download_result } } <- { :download , result } ,
971
+ with { :download , { lib_name , download_result } } <- { :download , result } ,
923
972
{ :download_result , { :ok , body } } <- { :download_result , download_result } ,
924
973
hash <- :crypto . hash ( @ checksum_algo , body ) ,
925
- path <- Path . join ( cache_dir , basename_from_url ( url ) ) ,
974
+ path <- Path . join ( cache_dir , lib_name ) ,
926
975
{ :file , :ok } <- { :file , File . write ( path , body ) } do
927
976
checksum = Base . encode16 ( hash , case: :lower )
928
977
@@ -932,7 +981,7 @@ defmodule RustlerPrecompiled do
932
981
933
982
[
934
983
% {
935
- url: url ,
984
+ lib_name: lib_name ,
936
985
path: path ,
937
986
checksum: checksum ,
938
987
checksum_algo: @ checksum_algo
@@ -986,14 +1035,6 @@ defmodule RustlerPrecompiled do
986
1035
end )
987
1036
end
988
1037
989
- defp basename_from_url ( url ) do
990
- uri = URI . parse ( url )
991
-
992
- uri . path
993
- |> String . split ( "/" )
994
- |> List . last ( )
995
- end
996
-
997
1038
defp read_map_from_file ( file ) do
998
1039
with { :ok , contents } <- File . read ( file ) ,
999
1040
{ % { } = contents , _ } <- Code . eval_string ( contents ) do
0 commit comments