├── .formatter.exs ├── .gitignore ├── README.md ├── assets ├── css │ └── app.css ├── js │ └── app.js ├── tailwind.config.js └── vendor │ └── topbar.js ├── config ├── config.exs ├── dev.exs ├── prod.exs ├── runtime.exs └── test.exs ├── lib ├── elixir_pdf.ex ├── elixir_pdf │ ├── application.ex │ ├── mailer.ex │ └── pdf_document.ex ├── elixir_pdf_web.ex ├── elixir_pdf_web │ ├── components │ │ ├── core_components.ex │ │ ├── layouts.ex │ │ └── layouts │ │ │ ├── app.html.heex │ │ │ └── root.html.heex │ ├── controllers │ │ ├── error_html.ex │ │ ├── error_json.ex │ │ ├── page_controller.ex │ │ ├── page_html.ex │ │ └── page_html │ │ │ └── home.html.heex │ ├── endpoint.ex │ ├── gettext.ex │ ├── live │ │ ├── home_live.ex │ │ └── home_live.html.heex │ ├── router.ex │ └── telemetry.ex └── rust_reader.ex ├── mix.exs ├── mix.lock ├── native └── rustreader │ ├── .cargo │ └── config.toml │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ └── src │ └── lib.rs ├── priv ├── gettext │ ├── en │ │ └── LC_MESSAGES │ │ │ └── errors.po │ └── errors.pot ├── native │ └── librustreader.so └── static │ ├── favicon.ico │ ├── images │ └── logo.svg │ └── robots.txt └── test ├── elixir_pdf_web └── controllers │ ├── error_html_test.exs │ ├── error_json_test.exs │ └── page_controller_test.exs ├── support └── conn_case.ex └── test_helper.exs /.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:phoenix], 3 | plugins: [Phoenix.LiveView.HTMLFormatter], 4 | inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}"] 5 | ] 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where 3rd-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Temporary files, for example, from tests. 23 | /tmp/ 24 | 25 | # Ignore package tarball (built via "mix hex.build"). 26 | elixir_pdf-*.tar 27 | 28 | # Ignore assets that are produced by build tools. 29 | /priv/static/assets/ 30 | /priv/static/uploads/ 31 | 32 | # Ignore digested assets cache. 33 | /priv/static/cache_manifest.json 34 | 35 | # In case you use Node.js/npm, you want to ignore these. 36 | npm-debug.log 37 | /assets/node_modules/ 38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ElixirPdf 2 | 3 | To start your Phoenix server: 4 | 5 | * Run `mix setup` to install and setup dependencies 6 | * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server` 7 | 8 | Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. 9 | 10 | Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). 11 | 12 | ## Learn more 13 | 14 | * Official website: https://www.phoenixframework.org/ 15 | * Guides: https://hexdocs.pm/phoenix/overview.html 16 | * Docs: https://hexdocs.pm/phoenix 17 | * Forum: https://elixirforum.com/c/phoenix-forum 18 | * Source: https://github.com/phoenixframework/phoenix 19 | -------------------------------------------------------------------------------- /assets/css/app.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss/base"; 2 | @import "tailwindcss/components"; 3 | @import "tailwindcss/utilities"; 4 | 5 | /* This file is for your main application CSS */ 6 | -------------------------------------------------------------------------------- /assets/js/app.js: -------------------------------------------------------------------------------- 1 | // If you want to use Phoenix channels, run `mix help phx.gen.channel` 2 | // to get started and then uncomment the line below. 3 | // import "./user_socket.js" 4 | 5 | // You can include dependencies in two ways. 6 | // 7 | // The simplest option is to put them in assets/vendor and 8 | // import them using relative paths: 9 | // 10 | // import "../vendor/some-package.js" 11 | // 12 | // Alternatively, you can `npm install some-package --prefix assets` and import 13 | // them using a path starting with the package name: 14 | // 15 | // import "some-package" 16 | // 17 | 18 | // Include phoenix_html to handle method=PUT/DELETE in forms and buttons. 19 | import "phoenix_html" 20 | // Establish Phoenix Socket and LiveView configuration. 21 | import {Socket} from "phoenix" 22 | import {LiveSocket} from "phoenix_live_view" 23 | import topbar from "../vendor/topbar" 24 | 25 | let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") 26 | let liveSocket = new LiveSocket("/live", Socket, { 27 | longPollFallbackMs: 2500, 28 | params: {_csrf_token: csrfToken} 29 | }) 30 | 31 | // Show progress bar on live navigation and form submits 32 | topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) 33 | window.addEventListener("phx:page-loading-start", _info => topbar.show(300)) 34 | window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) 35 | 36 | // connect if there are any LiveViews on the page 37 | liveSocket.connect() 38 | 39 | // expose liveSocket on window for web console debug logs and latency simulation: 40 | // >> liveSocket.enableDebug() 41 | // >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session 42 | // >> liveSocket.disableLatencySim() 43 | window.liveSocket = liveSocket 44 | 45 | -------------------------------------------------------------------------------- /assets/tailwind.config.js: -------------------------------------------------------------------------------- 1 | // See the Tailwind configuration guide for advanced usage 2 | // https://tailwindcss.com/docs/configuration 3 | 4 | const plugin = require("tailwindcss/plugin") 5 | const fs = require("fs") 6 | const path = require("path") 7 | 8 | module.exports = { 9 | content: [ 10 | "./js/**/*.js", 11 | "../lib/elixir_pdf_web.ex", 12 | "../lib/elixir_pdf_web/**/*.*ex" 13 | ], 14 | theme: { 15 | extend: { 16 | colors: { 17 | brand: "#FD4F00", 18 | } 19 | }, 20 | }, 21 | plugins: [ 22 | require("@tailwindcss/forms"), 23 | // Allows prefixing tailwind classes with LiveView classes to add rules 24 | // only when LiveView classes are applied, for example: 25 | // 26 | //
27 | // 28 | plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])), 29 | plugin(({addVariant}) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])), 30 | plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])), 31 | 32 | // Embeds Heroicons (https://heroicons.com) into your app.css bundle 33 | // See your `CoreComponents.icon/1` for more information. 34 | // 35 | plugin(function({matchComponents, theme}) { 36 | let iconsDir = path.join(__dirname, "../deps/heroicons/optimized") 37 | let values = {} 38 | let icons = [ 39 | ["", "/24/outline"], 40 | ["-solid", "/24/solid"], 41 | ["-mini", "/20/solid"], 42 | ["-micro", "/16/solid"] 43 | ] 44 | icons.forEach(([suffix, dir]) => { 45 | fs.readdirSync(path.join(iconsDir, dir)).forEach(file => { 46 | let name = path.basename(file, ".svg") + suffix 47 | values[name] = {name, fullPath: path.join(iconsDir, dir, file)} 48 | }) 49 | }) 50 | matchComponents({ 51 | "hero": ({name, fullPath}) => { 52 | let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "") 53 | let size = theme("spacing.6") 54 | if (name.endsWith("-mini")) { 55 | size = theme("spacing.5") 56 | } else if (name.endsWith("-micro")) { 57 | size = theme("spacing.4") 58 | } 59 | return { 60 | [`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`, 61 | "-webkit-mask": `var(--hero-${name})`, 62 | "mask": `var(--hero-${name})`, 63 | "mask-repeat": "no-repeat", 64 | "background-color": "currentColor", 65 | "vertical-align": "middle", 66 | "display": "inline-block", 67 | "width": size, 68 | "height": size 69 | } 70 | } 71 | }, {values}) 72 | }) 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /assets/vendor/topbar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license MIT 3 | * topbar 2.0.0, 2023-02-04 4 | * https://buunguyen.github.io/topbar 5 | * Copyright (c) 2021 Buu Nguyen 6 | */ 7 | (function (window, document) { 8 | "use strict"; 9 | 10 | // https://gist.github.com/paulirish/1579671 11 | (function () { 12 | var lastTime = 0; 13 | var vendors = ["ms", "moz", "webkit", "o"]; 14 | for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 15 | window.requestAnimationFrame = 16 | window[vendors[x] + "RequestAnimationFrame"]; 17 | window.cancelAnimationFrame = 18 | window[vendors[x] + "CancelAnimationFrame"] || 19 | window[vendors[x] + "CancelRequestAnimationFrame"]; 20 | } 21 | if (!window.requestAnimationFrame) 22 | window.requestAnimationFrame = function (callback, element) { 23 | var currTime = new Date().getTime(); 24 | var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 25 | var id = window.setTimeout(function () { 26 | callback(currTime + timeToCall); 27 | }, timeToCall); 28 | lastTime = currTime + timeToCall; 29 | return id; 30 | }; 31 | if (!window.cancelAnimationFrame) 32 | window.cancelAnimationFrame = function (id) { 33 | clearTimeout(id); 34 | }; 35 | })(); 36 | 37 | var canvas, 38 | currentProgress, 39 | showing, 40 | progressTimerId = null, 41 | fadeTimerId = null, 42 | delayTimerId = null, 43 | addEvent = function (elem, type, handler) { 44 | if (elem.addEventListener) elem.addEventListener(type, handler, false); 45 | else if (elem.attachEvent) elem.attachEvent("on" + type, handler); 46 | else elem["on" + type] = handler; 47 | }, 48 | options = { 49 | autoRun: true, 50 | barThickness: 3, 51 | barColors: { 52 | 0: "rgba(26, 188, 156, .9)", 53 | ".25": "rgba(52, 152, 219, .9)", 54 | ".50": "rgba(241, 196, 15, .9)", 55 | ".75": "rgba(230, 126, 34, .9)", 56 | "1.0": "rgba(211, 84, 0, .9)", 57 | }, 58 | shadowBlur: 10, 59 | shadowColor: "rgba(0, 0, 0, .6)", 60 | className: null, 61 | }, 62 | repaint = function () { 63 | canvas.width = window.innerWidth; 64 | canvas.height = options.barThickness * 5; // need space for shadow 65 | 66 | var ctx = canvas.getContext("2d"); 67 | ctx.shadowBlur = options.shadowBlur; 68 | ctx.shadowColor = options.shadowColor; 69 | 70 | var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); 71 | for (var stop in options.barColors) 72 | lineGradient.addColorStop(stop, options.barColors[stop]); 73 | ctx.lineWidth = options.barThickness; 74 | ctx.beginPath(); 75 | ctx.moveTo(0, options.barThickness / 2); 76 | ctx.lineTo( 77 | Math.ceil(currentProgress * canvas.width), 78 | options.barThickness / 2 79 | ); 80 | ctx.strokeStyle = lineGradient; 81 | ctx.stroke(); 82 | }, 83 | createCanvas = function () { 84 | canvas = document.createElement("canvas"); 85 | var style = canvas.style; 86 | style.position = "fixed"; 87 | style.top = style.left = style.right = style.margin = style.padding = 0; 88 | style.zIndex = 100001; 89 | style.display = "none"; 90 | if (options.className) canvas.classList.add(options.className); 91 | document.body.appendChild(canvas); 92 | addEvent(window, "resize", repaint); 93 | }, 94 | topbar = { 95 | config: function (opts) { 96 | for (var key in opts) 97 | if (options.hasOwnProperty(key)) options[key] = opts[key]; 98 | }, 99 | show: function (delay) { 100 | if (showing) return; 101 | if (delay) { 102 | if (delayTimerId) return; 103 | delayTimerId = setTimeout(() => topbar.show(), delay); 104 | } else { 105 | showing = true; 106 | if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId); 107 | if (!canvas) createCanvas(); 108 | canvas.style.opacity = 1; 109 | canvas.style.display = "block"; 110 | topbar.progress(0); 111 | if (options.autoRun) { 112 | (function loop() { 113 | progressTimerId = window.requestAnimationFrame(loop); 114 | topbar.progress( 115 | "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) 116 | ); 117 | })(); 118 | } 119 | } 120 | }, 121 | progress: function (to) { 122 | if (typeof to === "undefined") return currentProgress; 123 | if (typeof to === "string") { 124 | to = 125 | (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 126 | ? currentProgress 127 | : 0) + parseFloat(to); 128 | } 129 | currentProgress = to > 1 ? 1 : to; 130 | repaint(); 131 | return currentProgress; 132 | }, 133 | hide: function () { 134 | clearTimeout(delayTimerId); 135 | delayTimerId = null; 136 | if (!showing) return; 137 | showing = false; 138 | if (progressTimerId != null) { 139 | window.cancelAnimationFrame(progressTimerId); 140 | progressTimerId = null; 141 | } 142 | (function loop() { 143 | if (topbar.progress("+.1") >= 1) { 144 | canvas.style.opacity -= 0.05; 145 | if (canvas.style.opacity <= 0.05) { 146 | canvas.style.display = "none"; 147 | fadeTimerId = null; 148 | return; 149 | } 150 | } 151 | fadeTimerId = window.requestAnimationFrame(loop); 152 | })(); 153 | }, 154 | }; 155 | 156 | if (typeof module === "object" && typeof module.exports === "object") { 157 | module.exports = topbar; 158 | } else if (typeof define === "function" && define.amd) { 159 | define(function () { 160 | return topbar; 161 | }); 162 | } else { 163 | this.topbar = topbar; 164 | } 165 | }.call(this, window, document)); 166 | -------------------------------------------------------------------------------- /config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Config module. 3 | # 4 | # This configuration file is loaded before any dependency and 5 | # is restricted to this project. 6 | 7 | # General application configuration 8 | import Config 9 | 10 | config :elixir_pdf, 11 | generators: [timestamp_type: :utc_datetime] 12 | 13 | # Configures the endpoint 14 | config :elixir_pdf, ElixirPdfWeb.Endpoint, 15 | url: [host: "localhost"], 16 | adapter: Bandit.PhoenixAdapter, 17 | render_errors: [ 18 | formats: [html: ElixirPdfWeb.ErrorHTML, json: ElixirPdfWeb.ErrorJSON], 19 | layout: false 20 | ], 21 | pubsub_server: ElixirPdf.PubSub, 22 | live_view: [signing_salt: "D6OhZWbQ"] 23 | 24 | # Configures the mailer 25 | # 26 | # By default it uses the "Local" adapter which stores the emails 27 | # locally. You can see the emails in your browser, at "/dev/mailbox". 28 | # 29 | # For production it's recommended to configure a different adapter 30 | # at the `config/runtime.exs`. 31 | config :elixir_pdf, ElixirPdf.Mailer, adapter: Swoosh.Adapters.Local 32 | 33 | # Configure esbuild (the version is required) 34 | config :esbuild, 35 | version: "0.17.11", 36 | elixir_pdf: [ 37 | args: 38 | ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), 39 | cd: Path.expand("../assets", __DIR__), 40 | env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} 41 | ] 42 | 43 | # Configure tailwind (the version is required) 44 | config :tailwind, 45 | version: "3.4.3", 46 | elixir_pdf: [ 47 | args: ~w( 48 | --config=tailwind.config.js 49 | --input=css/app.css 50 | --output=../priv/static/assets/app.css 51 | ), 52 | cd: Path.expand("../assets", __DIR__) 53 | ] 54 | 55 | # Configures Elixir's Logger 56 | config :logger, :console, 57 | format: "$time $metadata[$level] $message\n", 58 | metadata: [:request_id] 59 | 60 | # Use Jason for JSON parsing in Phoenix 61 | config :phoenix, :json_library, Jason 62 | 63 | # Import environment specific config. This must remain at the bottom 64 | # of this file so it overrides the configuration defined above. 65 | import_config "#{config_env()}.exs" 66 | -------------------------------------------------------------------------------- /config/dev.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # For development, we disable any cache and enable 4 | # debugging and code reloading. 5 | # 6 | # The watchers configuration can be used to run external 7 | # watchers to your application. For example, we can use it 8 | # to bundle .js and .css sources. 9 | config :elixir_pdf, ElixirPdfWeb.Endpoint, 10 | # Binding to loopback ipv4 address prevents access from other machines. 11 | # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. 12 | http: [ip: {127, 0, 0, 1}, port: 4000], 13 | check_origin: false, 14 | code_reloader: true, 15 | debug_errors: true, 16 | secret_key_base: "uIR0q4FwSTt4ILo0dJHn8Oi1x8Anb1dFaCKTvH9N2u0+oN4Gu081jY4uboux/ifj", 17 | watchers: [ 18 | esbuild: {Esbuild, :install_and_run, [:elixir_pdf, ~w(--sourcemap=inline --watch)]}, 19 | tailwind: {Tailwind, :install_and_run, [:elixir_pdf, ~w(--watch)]} 20 | ] 21 | 22 | # ## SSL Support 23 | # 24 | # In order to use HTTPS in development, a self-signed 25 | # certificate can be generated by running the following 26 | # Mix task: 27 | # 28 | # mix phx.gen.cert 29 | # 30 | # Run `mix help phx.gen.cert` for more information. 31 | # 32 | # The `http:` config above can be replaced with: 33 | # 34 | # https: [ 35 | # port: 4001, 36 | # cipher_suite: :strong, 37 | # keyfile: "priv/cert/selfsigned_key.pem", 38 | # certfile: "priv/cert/selfsigned.pem" 39 | # ], 40 | # 41 | # If desired, both `http:` and `https:` keys can be 42 | # configured to run both http and https servers on 43 | # different ports. 44 | 45 | # Watch static and templates for browser reloading. 46 | config :elixir_pdf, ElixirPdfWeb.Endpoint, 47 | live_reload: [ 48 | patterns: [ 49 | ~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$", 50 | ~r"priv/gettext/.*(po)$", 51 | ~r"lib/elixir_pdf_web/(controllers|live|components)/.*(ex|heex)$" 52 | ] 53 | ] 54 | 55 | # Enable dev routes for dashboard and mailbox 56 | config :elixir_pdf, dev_routes: true 57 | 58 | # Do not include metadata nor timestamps in development logs 59 | config :logger, :console, format: "[$level] $message\n" 60 | 61 | # Set a higher stacktrace during development. Avoid configuring such 62 | # in production as building large stacktraces may be expensive. 63 | config :phoenix, :stacktrace_depth, 20 64 | 65 | # Initialize plugs at runtime for faster development compilation 66 | config :phoenix, :plug_init_mode, :runtime 67 | 68 | config :phoenix_live_view, 69 | # Include HEEx debug annotations as HTML comments in rendered markup 70 | debug_heex_annotations: true, 71 | # Enable helpful, but potentially expensive runtime checks 72 | enable_expensive_runtime_checks: true 73 | 74 | # Disable swoosh api client as it is only required for production adapters. 75 | config :swoosh, :api_client, false 76 | -------------------------------------------------------------------------------- /config/prod.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # Note we also include the path to a cache manifest 4 | # containing the digested version of static files. This 5 | # manifest is generated by the `mix assets.deploy` task, 6 | # which you should run after static files are built and 7 | # before starting your production server. 8 | config :elixir_pdf, ElixirPdfWeb.Endpoint, 9 | cache_static_manifest: "priv/static/cache_manifest.json" 10 | 11 | # Configures Swoosh API Client 12 | config :swoosh, api_client: Swoosh.ApiClient.Finch, finch_name: ElixirPdf.Finch 13 | 14 | # Disable Swoosh Local Memory Storage 15 | config :swoosh, local: false 16 | 17 | # Do not print debug messages in production 18 | config :logger, level: :info 19 | 20 | # Runtime production configuration, including reading 21 | # of environment variables, is done on config/runtime.exs. 22 | -------------------------------------------------------------------------------- /config/runtime.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # config/runtime.exs is executed for all environments, including 4 | # during releases. It is executed after compilation and before the 5 | # system starts, so it is typically used to load production configuration 6 | # and secrets from environment variables or elsewhere. Do not define 7 | # any compile-time configuration in here, as it won't be applied. 8 | # The block below contains prod specific runtime configuration. 9 | 10 | # ## Using releases 11 | # 12 | # If you use `mix release`, you need to explicitly enable the server 13 | # by passing the PHX_SERVER=true when you start it: 14 | # 15 | # PHX_SERVER=true bin/elixir_pdf start 16 | # 17 | # Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` 18 | # script that automatically sets the env var above. 19 | if System.get_env("PHX_SERVER") do 20 | config :elixir_pdf, ElixirPdfWeb.Endpoint, server: true 21 | end 22 | 23 | if config_env() == :prod do 24 | # The secret key base is used to sign/encrypt cookies and other secrets. 25 | # A default value is used in config/dev.exs and config/test.exs but you 26 | # want to use a different value for prod and you most likely don't want 27 | # to check this value into version control, so we use an environment 28 | # variable instead. 29 | secret_key_base = 30 | System.get_env("SECRET_KEY_BASE") || 31 | raise """ 32 | environment variable SECRET_KEY_BASE is missing. 33 | You can generate one by calling: mix phx.gen.secret 34 | """ 35 | 36 | host = System.get_env("PHX_HOST") || "example.com" 37 | port = String.to_integer(System.get_env("PORT") || "4000") 38 | 39 | config :elixir_pdf, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY") 40 | 41 | config :elixir_pdf, ElixirPdfWeb.Endpoint, 42 | url: [host: host, port: 443, scheme: "https"], 43 | http: [ 44 | # Enable IPv6 and bind on all interfaces. 45 | # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. 46 | # See the documentation on https://hexdocs.pm/bandit/Bandit.html#t:options/0 47 | # for details about using IPv6 vs IPv4 and loopback vs public addresses. 48 | ip: {0, 0, 0, 0, 0, 0, 0, 0}, 49 | port: port 50 | ], 51 | secret_key_base: secret_key_base 52 | 53 | # ## SSL Support 54 | # 55 | # To get SSL working, you will need to add the `https` key 56 | # to your endpoint configuration: 57 | # 58 | # config :elixir_pdf, ElixirPdfWeb.Endpoint, 59 | # https: [ 60 | # ..., 61 | # port: 443, 62 | # cipher_suite: :strong, 63 | # keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), 64 | # certfile: System.get_env("SOME_APP_SSL_CERT_PATH") 65 | # ] 66 | # 67 | # The `cipher_suite` is set to `:strong` to support only the 68 | # latest and more secure SSL ciphers. This means old browsers 69 | # and clients may not be supported. You can set it to 70 | # `:compatible` for wider support. 71 | # 72 | # `:keyfile` and `:certfile` expect an absolute path to the key 73 | # and cert in disk or a relative path inside priv, for example 74 | # "priv/ssl/server.key". For all supported SSL configuration 75 | # options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1 76 | # 77 | # We also recommend setting `force_ssl` in your config/prod.exs, 78 | # ensuring no data is ever sent via http, always redirecting to https: 79 | # 80 | # config :elixir_pdf, ElixirPdfWeb.Endpoint, 81 | # force_ssl: [hsts: true] 82 | # 83 | # Check `Plug.SSL` for all available options in `force_ssl`. 84 | 85 | # ## Configuring the mailer 86 | # 87 | # In production you need to configure the mailer to use a different adapter. 88 | # Also, you may need to configure the Swoosh API client of your choice if you 89 | # are not using SMTP. Here is an example of the configuration: 90 | # 91 | # config :elixir_pdf, ElixirPdf.Mailer, 92 | # adapter: Swoosh.Adapters.Mailgun, 93 | # api_key: System.get_env("MAILGUN_API_KEY"), 94 | # domain: System.get_env("MAILGUN_DOMAIN") 95 | # 96 | # For this example you need include a HTTP client required by Swoosh API client. 97 | # Swoosh supports Hackney and Finch out of the box: 98 | # 99 | # config :swoosh, :api_client, Swoosh.ApiClient.Hackney 100 | # 101 | # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details. 102 | end 103 | -------------------------------------------------------------------------------- /config/test.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # We don't run a server during test. If one is required, 4 | # you can enable the server option below. 5 | config :elixir_pdf, ElixirPdfWeb.Endpoint, 6 | http: [ip: {127, 0, 0, 1}, port: 4002], 7 | secret_key_base: "SVslpB566z8UcO6CzJfup/JOvn6Ig12wYInVYaskHKYVuPda+m0a6TATF7+K6xeX", 8 | server: false 9 | 10 | # In test we don't send emails 11 | config :elixir_pdf, ElixirPdf.Mailer, adapter: Swoosh.Adapters.Test 12 | 13 | # Disable swoosh api client as it is only required for production adapters 14 | config :swoosh, :api_client, false 15 | 16 | # Print only warnings and errors during test 17 | config :logger, level: :warning 18 | 19 | # Initialize plugs at runtime for faster test compilation 20 | config :phoenix, :plug_init_mode, :runtime 21 | 22 | # Enable helpful, but potentially expensive runtime checks 23 | config :phoenix_live_view, 24 | enable_expensive_runtime_checks: true 25 | -------------------------------------------------------------------------------- /lib/elixir_pdf.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdf do 2 | @moduledoc """ 3 | ElixirPdf keeps the contexts that define your domain 4 | and business logic. 5 | 6 | Contexts are also responsible for managing your data, regardless 7 | if it comes from the database, an external API or others. 8 | """ 9 | end 10 | -------------------------------------------------------------------------------- /lib/elixir_pdf/application.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdf.Application do 2 | # See https://hexdocs.pm/elixir/Application.html 3 | # for more information on OTP Applications 4 | @moduledoc false 5 | 6 | use Application 7 | 8 | @impl true 9 | def start(_type, _args) do 10 | children = [ 11 | ElixirPdfWeb.Telemetry, 12 | {DNSCluster, query: Application.get_env(:elixir_pdf, :dns_cluster_query) || :ignore}, 13 | {Phoenix.PubSub, name: ElixirPdf.PubSub}, 14 | # Start the Finch HTTP client for sending emails 15 | {Finch, name: ElixirPdf.Finch}, 16 | # Start a worker by calling: ElixirPdf.Worker.start_link(arg) 17 | # {ElixirPdf.Worker, arg}, 18 | # Start to serve requests, typically the last entry 19 | ElixirPdfWeb.Endpoint 20 | ] 21 | 22 | # See https://hexdocs.pm/elixir/Supervisor.html 23 | # for other strategies and supported options 24 | opts = [strategy: :one_for_one, name: ElixirPdf.Supervisor] 25 | Supervisor.start_link(children, opts) 26 | end 27 | 28 | # Tell Phoenix to update the endpoint configuration 29 | # whenever the application is updated. 30 | @impl true 31 | def config_change(changed, _new, removed) do 32 | ElixirPdfWeb.Endpoint.config_change(changed, removed) 33 | :ok 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/elixir_pdf/mailer.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdf.Mailer do 2 | use Swoosh.Mailer, otp_app: :elixir_pdf 3 | end 4 | -------------------------------------------------------------------------------- /lib/elixir_pdf/pdf_document.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdf.PdfDocument do 2 | @derive {Jason.Encoder, only: [:content, :metadata]} 3 | defstruct [:content, :metadata] 4 | 5 | def from_rustler({content, metadata_json}) do 6 | with {:ok, metadata} <- Jason.decode(metadata_json) do 7 | %__MODULE__{ 8 | content: String.trim(content), 9 | metadata: metadata 10 | } 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb do 2 | @moduledoc """ 3 | The entrypoint for defining your web interface, such 4 | as controllers, components, channels, and so on. 5 | 6 | This can be used in your application as: 7 | 8 | use ElixirPdfWeb, :controller 9 | use ElixirPdfWeb, :html 10 | 11 | The definitions below will be executed for every controller, 12 | component, etc, so keep them short and clean, focused 13 | on imports, uses and aliases. 14 | 15 | Do NOT define functions inside the quoted expressions 16 | below. Instead, define additional modules and import 17 | those modules here. 18 | """ 19 | 20 | def static_paths, do: ~w(assets fonts images favicon.ico robots.txt) 21 | 22 | def router do 23 | quote do 24 | use Phoenix.Router, helpers: false 25 | 26 | # Import common connection and controller functions to use in pipelines 27 | import Plug.Conn 28 | import Phoenix.Controller 29 | import Phoenix.LiveView.Router 30 | end 31 | end 32 | 33 | def channel do 34 | quote do 35 | use Phoenix.Channel 36 | end 37 | end 38 | 39 | def controller do 40 | quote do 41 | use Phoenix.Controller, 42 | formats: [:html, :json], 43 | layouts: [html: ElixirPdfWeb.Layouts] 44 | 45 | use Gettext, backend: ElixirPdfWeb.Gettext 46 | 47 | import Plug.Conn 48 | 49 | unquote(verified_routes()) 50 | end 51 | end 52 | 53 | def live_view do 54 | quote do 55 | use Phoenix.LiveView, 56 | layout: {ElixirPdfWeb.Layouts, :app} 57 | 58 | unquote(html_helpers()) 59 | end 60 | end 61 | 62 | def live_component do 63 | quote do 64 | use Phoenix.LiveComponent 65 | 66 | unquote(html_helpers()) 67 | end 68 | end 69 | 70 | def html do 71 | quote do 72 | use Phoenix.Component 73 | 74 | # Import convenience functions from controllers 75 | import Phoenix.Controller, 76 | only: [get_csrf_token: 0, view_module: 1, view_template: 1] 77 | 78 | # Include general helpers for rendering HTML 79 | unquote(html_helpers()) 80 | end 81 | end 82 | 83 | defp html_helpers do 84 | quote do 85 | # Translation 86 | use Gettext, backend: ElixirPdfWeb.Gettext 87 | 88 | # HTML escaping functionality 89 | import Phoenix.HTML 90 | # Core UI components 91 | import ElixirPdfWeb.CoreComponents 92 | 93 | # Shortcut for generating JS commands 94 | alias Phoenix.LiveView.JS 95 | 96 | # Routes generation with the ~p sigil 97 | unquote(verified_routes()) 98 | end 99 | end 100 | 101 | def verified_routes do 102 | quote do 103 | use Phoenix.VerifiedRoutes, 104 | endpoint: ElixirPdfWeb.Endpoint, 105 | router: ElixirPdfWeb.Router, 106 | statics: ElixirPdfWeb.static_paths() 107 | end 108 | end 109 | 110 | @doc """ 111 | When used, dispatch to the appropriate controller/live_view/etc. 112 | """ 113 | defmacro __using__(which) when is_atom(which) do 114 | apply(__MODULE__, which, []) 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/components/core_components.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.CoreComponents do 2 | @moduledoc """ 3 | Provides core UI components. 4 | 5 | At first glance, this module may seem daunting, but its goal is to provide 6 | core building blocks for your application, such as modals, tables, and 7 | forms. The components consist mostly of markup and are well-documented 8 | with doc strings and declarative assigns. You may customize and style 9 | them in any way you want, based on your application growth and needs. 10 | 11 | The default components use Tailwind CSS, a utility-first CSS framework. 12 | See the [Tailwind CSS documentation](https://tailwindcss.com) to learn 13 | how to customize them or feel free to swap in another framework altogether. 14 | 15 | Icons are provided by [heroicons](https://heroicons.com). See `icon/1` for usage. 16 | """ 17 | use Phoenix.Component 18 | use Gettext, backend: ElixirPdfWeb.Gettext 19 | 20 | alias Phoenix.LiveView.JS 21 | 22 | @doc """ 23 | Renders a modal. 24 | 25 | ## Examples 26 | 27 | <.modal id="confirm-modal"> 28 | This is a modal. 29 | 30 | 31 | JS commands may be passed to the `:on_cancel` to configure 32 | the closing/cancel event, for example: 33 | 34 | <.modal id="confirm" on_cancel={JS.navigate(~p"/posts")}> 35 | This is another modal. 36 | 37 | 38 | """ 39 | attr :id, :string, required: true 40 | attr :show, :boolean, default: false 41 | attr :on_cancel, JS, default: %JS{} 42 | slot :inner_block, required: true 43 | 44 | def modal(assigns) do 45 | ~H""" 46 | 328 | """ 329 | end 330 | 331 | def input(%{type: "select"} = assigns) do 332 | ~H""" 333 |
334 | <.label for={@id}>{@label} 335 | 345 | <.error :for={msg <- @errors}>{msg} 346 |
347 | """ 348 | end 349 | 350 | def input(%{type: "textarea"} = assigns) do 351 | ~H""" 352 |
353 | <.label for={@id}>{@label} 354 | 364 | <.error :for={msg <- @errors}>{msg} 365 |
366 | """ 367 | end 368 | 369 | # All other inputs text, datetime-local, url, password, etc. are handled here... 370 | def input(assigns) do 371 | ~H""" 372 |
373 | <.label for={@id}>{@label} 374 | 386 | <.error :for={msg <- @errors}>{msg} 387 |
388 | """ 389 | end 390 | 391 | @doc """ 392 | Renders a label. 393 | """ 394 | attr :for, :string, default: nil 395 | slot :inner_block, required: true 396 | 397 | def label(assigns) do 398 | ~H""" 399 | 402 | """ 403 | end 404 | 405 | @doc """ 406 | Generates a generic error message. 407 | """ 408 | slot :inner_block, required: true 409 | 410 | def error(assigns) do 411 | ~H""" 412 |

413 | <.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" /> 414 | {render_slot(@inner_block)} 415 |

416 | """ 417 | end 418 | 419 | @doc """ 420 | Renders a header with title. 421 | """ 422 | attr :class, :string, default: nil 423 | 424 | slot :inner_block, required: true 425 | slot :subtitle 426 | slot :actions 427 | 428 | def header(assigns) do 429 | ~H""" 430 |
431 |
432 |

433 | {render_slot(@inner_block)} 434 |

435 |

436 | {render_slot(@subtitle)} 437 |

438 |
439 |
{render_slot(@actions)}
440 |
441 | """ 442 | end 443 | 444 | @doc ~S""" 445 | Renders a table with generic styling. 446 | 447 | ## Examples 448 | 449 | <.table id="users" rows={@users}> 450 | <:col :let={user} label="id">{user.id} 451 | <:col :let={user} label="username">{user.username} 452 | 453 | """ 454 | attr :id, :string, required: true 455 | attr :rows, :list, required: true 456 | attr :row_id, :any, default: nil, doc: "the function for generating the row id" 457 | attr :row_click, :any, default: nil, doc: "the function for handling phx-click on each row" 458 | 459 | attr :row_item, :any, 460 | default: &Function.identity/1, 461 | doc: "the function for mapping each row before calling the :col and :action slots" 462 | 463 | slot :col, required: true do 464 | attr :label, :string 465 | end 466 | 467 | slot :action, doc: "the slot for showing user actions in the last table column" 468 | 469 | def table(assigns) do 470 | assigns = 471 | with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do 472 | assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end) 473 | end 474 | 475 | ~H""" 476 |
477 | 478 | 479 | 480 | 481 | 484 | 485 | 486 | 491 | 492 | 504 | 515 | 516 | 517 |
{col[:label]} 482 | {gettext("Actions")} 483 |
497 |
498 | 499 | 500 | {render_slot(col, @row_item.(row))} 501 | 502 |
503 |
505 |
506 | 507 | 511 | {render_slot(action, @row_item.(row))} 512 | 513 |
514 |
518 |
519 | """ 520 | end 521 | 522 | @doc """ 523 | Renders a data list. 524 | 525 | ## Examples 526 | 527 | <.list> 528 | <:item title="Title">{@post.title} 529 | <:item title="Views">{@post.views} 530 | 531 | """ 532 | slot :item, required: true do 533 | attr :title, :string, required: true 534 | end 535 | 536 | def list(assigns) do 537 | ~H""" 538 |
539 |
540 |
541 |
{item.title}
542 |
{render_slot(item)}
543 |
544 |
545 |
546 | """ 547 | end 548 | 549 | @doc """ 550 | Renders a back navigation link. 551 | 552 | ## Examples 553 | 554 | <.back navigate={~p"/posts"}>Back to posts 555 | """ 556 | attr :navigate, :any, required: true 557 | slot :inner_block, required: true 558 | 559 | def back(assigns) do 560 | ~H""" 561 |
562 | <.link 563 | navigate={@navigate} 564 | class="text-sm font-semibold leading-6 text-zinc-900 hover:text-zinc-700" 565 | > 566 | <.icon name="hero-arrow-left-solid" class="h-3 w-3" /> 567 | {render_slot(@inner_block)} 568 | 569 |
570 | """ 571 | end 572 | 573 | @doc """ 574 | Renders a [Heroicon](https://heroicons.com). 575 | 576 | Heroicons come in three styles – outline, solid, and mini. 577 | By default, the outline style is used, but solid and mini may 578 | be applied by using the `-solid` and `-mini` suffix. 579 | 580 | You can customize the size and colors of the icons by setting 581 | width, height, and background color classes. 582 | 583 | Icons are extracted from the `deps/heroicons` directory and bundled within 584 | your compiled app.css by the plugin in your `assets/tailwind.config.js`. 585 | 586 | ## Examples 587 | 588 | <.icon name="hero-x-mark-solid" /> 589 | <.icon name="hero-arrow-path" class="ml-1 w-3 h-3 animate-spin" /> 590 | """ 591 | attr :name, :string, required: true 592 | attr :class, :string, default: nil 593 | 594 | def icon(%{name: "hero-" <> _} = assigns) do 595 | ~H""" 596 | 597 | """ 598 | end 599 | 600 | ## JS Commands 601 | 602 | def show(js \\ %JS{}, selector) do 603 | JS.show(js, 604 | to: selector, 605 | time: 300, 606 | transition: 607 | {"transition-all transform ease-out duration-300", 608 | "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95", 609 | "opacity-100 translate-y-0 sm:scale-100"} 610 | ) 611 | end 612 | 613 | def hide(js \\ %JS{}, selector) do 614 | JS.hide(js, 615 | to: selector, 616 | time: 200, 617 | transition: 618 | {"transition-all transform ease-in duration-200", 619 | "opacity-100 translate-y-0 sm:scale-100", 620 | "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"} 621 | ) 622 | end 623 | 624 | def show_modal(js \\ %JS{}, id) when is_binary(id) do 625 | js 626 | |> JS.show(to: "##{id}") 627 | |> JS.show( 628 | to: "##{id}-bg", 629 | time: 300, 630 | transition: {"transition-all transform ease-out duration-300", "opacity-0", "opacity-100"} 631 | ) 632 | |> show("##{id}-container") 633 | |> JS.add_class("overflow-hidden", to: "body") 634 | |> JS.focus_first(to: "##{id}-content") 635 | end 636 | 637 | def hide_modal(js \\ %JS{}, id) do 638 | js 639 | |> JS.hide( 640 | to: "##{id}-bg", 641 | transition: {"transition-all transform ease-in duration-200", "opacity-100", "opacity-0"} 642 | ) 643 | |> hide("##{id}-container") 644 | |> JS.hide(to: "##{id}", transition: {"block", "block", "hidden"}) 645 | |> JS.remove_class("overflow-hidden", to: "body") 646 | |> JS.pop_focus() 647 | end 648 | 649 | @doc """ 650 | Translates an error message using gettext. 651 | """ 652 | def translate_error({msg, opts}) do 653 | # When using gettext, we typically pass the strings we want 654 | # to translate as a static argument: 655 | # 656 | # # Translate the number of files with plural rules 657 | # dngettext("errors", "1 file", "%{count} files", count) 658 | # 659 | # However the error messages in our forms and APIs are generated 660 | # dynamically, so we need to translate them by calling Gettext 661 | # with our gettext backend as first argument. Translations are 662 | # available in the errors.po file (as we use the "errors" domain). 663 | if count = opts[:count] do 664 | Gettext.dngettext(ElixirPdfWeb.Gettext, "errors", msg, msg, count, opts) 665 | else 666 | Gettext.dgettext(ElixirPdfWeb.Gettext, "errors", msg, opts) 667 | end 668 | end 669 | 670 | @doc """ 671 | Translates the errors for a field from a keyword list of errors. 672 | """ 673 | def translate_errors(errors, field) when is_list(errors) do 674 | for {^field, {msg, opts}} <- errors, do: translate_error({msg, opts}) 675 | end 676 | end 677 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/components/layouts.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.Layouts do 2 | @moduledoc """ 3 | This module holds different layouts used by your application. 4 | 5 | See the `layouts` directory for all templates available. 6 | The "root" layout is a skeleton rendered as part of the 7 | application router. The "app" layout is set as the default 8 | layout on both `use ElixirPdfWeb, :controller` and 9 | `use ElixirPdfWeb, :live_view`. 10 | """ 11 | use ElixirPdfWeb, :html 12 | 13 | embed_templates "layouts/*" 14 | end 15 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/components/layouts/app.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 | 7 |

8 | v{Application.spec(:phoenix, :vsn)} 9 |

10 |
11 | 25 |
26 |
27 |
28 |
29 | <.flash_group flash={@flash} /> 30 | {@inner_content} 31 |
32 |
33 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/components/layouts/root.html.heex: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <.live_title default="ElixirPdf" suffix=" · Phoenix Framework"> 8 | {assigns[:page_title]} 9 | 10 | 11 | 13 | 14 | 15 | {@inner_content} 16 | 17 | 18 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/controllers/error_html.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.ErrorHTML do 2 | @moduledoc """ 3 | This module is invoked by your endpoint in case of errors on HTML requests. 4 | 5 | See config/config.exs. 6 | """ 7 | use ElixirPdfWeb, :html 8 | 9 | # If you want to customize your error pages, 10 | # uncomment the embed_templates/1 call below 11 | # and add pages to the error directory: 12 | # 13 | # * lib/elixir_pdf_web/controllers/error_html/404.html.heex 14 | # * lib/elixir_pdf_web/controllers/error_html/500.html.heex 15 | # 16 | # embed_templates "error_html/*" 17 | 18 | # The default is to render a plain text page based on 19 | # the template name. For example, "404.html" becomes 20 | # "Not Found". 21 | def render(template, _assigns) do 22 | Phoenix.Controller.status_message_from_template(template) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/controllers/error_json.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.ErrorJSON do 2 | @moduledoc """ 3 | This module is invoked by your endpoint in case of errors on JSON requests. 4 | 5 | See config/config.exs. 6 | """ 7 | 8 | # If you want to customize a particular status code, 9 | # you may add your own clauses, such as: 10 | # 11 | # def render("500.json", _assigns) do 12 | # %{errors: %{detail: "Internal Server Error"}} 13 | # end 14 | 15 | # By default, Phoenix returns the status message from 16 | # the template name. For example, "404.json" becomes 17 | # "Not Found". 18 | def render(template, _assigns) do 19 | %{errors: %{detail: Phoenix.Controller.status_message_from_template(template)}} 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/controllers/page_controller.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.PageController do 2 | use ElixirPdfWeb, :controller 3 | 4 | def home(conn, _params) do 5 | # The home page is often custom made, 6 | # so skip the default app layout. 7 | render(conn, :home, layout: false) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/controllers/page_html.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.PageHTML do 2 | @moduledoc """ 3 | This module contains pages rendered by PageController. 4 | 5 | See the `page_html` directory for all templates available. 6 | """ 7 | use ElixirPdfWeb, :html 8 | 9 | embed_templates "page_html/*" 10 | end 11 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/controllers/page_html/home.html.heex: -------------------------------------------------------------------------------- 1 | <.flash_group flash={@flash} /> 2 | 41 |
42 |
43 | 49 |

50 | Phoenix Framework 51 | 52 | v{Application.spec(:phoenix, :vsn)} 53 | 54 |

55 |

56 | Peace of mind from prototype to production. 57 |

58 |

59 | Build rich, interactive web applications quickly, with less code and fewer moving parts. Join our growing community of developers using Phoenix to craft APIs, HTML5 apps and more, for fun or at scale. 60 |

61 | 221 |
222 |
223 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/endpoint.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.Endpoint do 2 | use Phoenix.Endpoint, otp_app: :elixir_pdf 3 | 4 | # The session will be stored in the cookie and signed, 5 | # this means its contents can be read but not tampered with. 6 | # Set :encryption_salt if you would also like to encrypt it. 7 | @session_options [ 8 | store: :cookie, 9 | key: "_elixir_pdf_key", 10 | signing_salt: "irzTllh7", 11 | same_site: "Lax" 12 | ] 13 | 14 | socket "/live", Phoenix.LiveView.Socket, 15 | websocket: [connect_info: [session: @session_options]], 16 | longpoll: [connect_info: [session: @session_options]] 17 | 18 | # Serve at "/" the static files from "priv/static" directory. 19 | # 20 | # You should set gzip to true if you are running phx.digest 21 | # when deploying your static files in production. 22 | plug Plug.Static, 23 | at: "/", 24 | from: :elixir_pdf, 25 | gzip: false, 26 | only: ElixirPdfWeb.static_paths() 27 | 28 | # Code reloading can be explicitly enabled under the 29 | # :code_reloader configuration of your endpoint. 30 | if code_reloading? do 31 | socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket 32 | plug Phoenix.LiveReloader 33 | plug Phoenix.CodeReloader 34 | end 35 | 36 | plug Phoenix.LiveDashboard.RequestLogger, 37 | param_key: "request_logger", 38 | cookie_key: "request_logger" 39 | 40 | plug Plug.RequestId 41 | plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] 42 | 43 | plug Plug.Parsers, 44 | parsers: [:urlencoded, :multipart, :json], 45 | pass: ["*/*"], 46 | json_decoder: Phoenix.json_library() 47 | 48 | plug Plug.MethodOverride 49 | plug Plug.Head 50 | plug Plug.Session, @session_options 51 | plug ElixirPdfWeb.Router 52 | end 53 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/gettext.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.Gettext do 2 | @moduledoc """ 3 | A module providing Internationalization with a gettext-based API. 4 | 5 | By using [Gettext](https://hexdocs.pm/gettext), your module compiles translations 6 | that you can use in your application. To use this Gettext backend module, 7 | call `use Gettext` and pass it as an option: 8 | 9 | use Gettext, backend: ElixirPdfWeb.Gettext 10 | 11 | # Simple translation 12 | gettext("Here is the string to translate") 13 | 14 | # Plural translation 15 | ngettext("Here is the string to translate", 16 | "Here are the strings to translate", 17 | 3) 18 | 19 | # Domain-based translation 20 | dgettext("errors", "Here is the error message to translate") 21 | 22 | See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. 23 | """ 24 | use Gettext.Backend, otp_app: :elixir_pdf 25 | end 26 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/live/home_live.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.HomeLive do 2 | use ElixirPdfWeb, :live_view 3 | 4 | @impl true 5 | def mount(_params, _session, socket) do 6 | {:ok, 7 | socket 8 | |> assign(:uploaded_files, []) 9 | |> allow_upload(:pdf, 10 | accept: ~w(.pdf), 11 | max_entries: 1, 12 | # 10MB limit 13 | max_file_size: 10_000_000, 14 | chunk_size: 64_000 15 | )} 16 | end 17 | 18 | @impl true 19 | def handle_event("validate", _params, socket) do 20 | {:noreply, socket} 21 | end 22 | 23 | @impl true 24 | def handle_event("save", _params, socket) do 25 | uploaded_files = 26 | consume_uploaded_entries(socket, :pdf, fn %{path: path}, _entry -> 27 | dest = Path.join(["priv", "static", "uploads", Path.basename(path)]) 28 | File.cp!(path, dest) 29 | {:ok, dest} 30 | end) 31 | 32 | pdf_document = 33 | uploaded_files 34 | |> hd() 35 | |> RustReader.extract_pdf() 36 | |> ElixirPdf.PdfDocument.from_rustler() 37 | |> IO.inspect() 38 | 39 | {:noreply, 40 | socket 41 | |> assign(:pdf_document, pdf_document) 42 | |> update(:uploaded_files, &(&1 ++ uploaded_files))} 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/live/home_live.html.heex: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Upload PDF

4 | 5 |
6 |
7 |
8 |
9 |
10 | Drag and drop your PDF here or 11 | 14 |
15 |

PDF files only, up to 10MB

16 |
17 |
18 | 19 | <%= for entry <- @uploads.pdf.entries do %> 20 |
21 |
22 |
23 | {entry.client_name} 24 | 25 | ({entry.client_size}B) 26 | 27 |
28 | 29 | 37 |
38 | 39 | <%= for err <- upload_errors(@uploads.pdf, entry) do %> 40 | <% end %> 41 |
42 | <% end %> 43 | 44 | <%= if length(@uploads.pdf.entries) > 0 do %> 45 | 51 | <% end %> 52 |
53 |
54 |
55 |
56 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/router.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.Router do 2 | use ElixirPdfWeb, :router 3 | 4 | pipeline :browser do 5 | plug :accepts, ["html"] 6 | plug :fetch_session 7 | plug :fetch_live_flash 8 | plug :put_root_layout, html: {ElixirPdfWeb.Layouts, :root} 9 | plug :protect_from_forgery 10 | plug :put_secure_browser_headers 11 | end 12 | 13 | pipeline :api do 14 | plug :accepts, ["json"] 15 | end 16 | 17 | scope "/", ElixirPdfWeb do 18 | pipe_through :browser 19 | 20 | live "/", HomeLive 21 | end 22 | 23 | # Other scopes may use custom stacks. 24 | # scope "/api", ElixirPdfWeb do 25 | # pipe_through :api 26 | # end 27 | 28 | # Enable LiveDashboard and Swoosh mailbox preview in development 29 | if Application.compile_env(:elixir_pdf, :dev_routes) do 30 | # If you want to use the LiveDashboard in production, you should put 31 | # it behind authentication and allow only admins to access it. 32 | # If your application does not have an admins-only section yet, 33 | # you can use Plug.BasicAuth to set up some basic authentication 34 | # as long as you are also using SSL (which you should anyway). 35 | import Phoenix.LiveDashboard.Router 36 | 37 | scope "/dev" do 38 | pipe_through :browser 39 | 40 | live_dashboard "/dashboard", metrics: ElixirPdfWeb.Telemetry 41 | forward "/mailbox", Plug.Swoosh.MailboxPreview 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/elixir_pdf_web/telemetry.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.Telemetry do 2 | use Supervisor 3 | import Telemetry.Metrics 4 | 5 | def start_link(arg) do 6 | Supervisor.start_link(__MODULE__, arg, name: __MODULE__) 7 | end 8 | 9 | @impl true 10 | def init(_arg) do 11 | children = [ 12 | # Telemetry poller will execute the given period measurements 13 | # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics 14 | {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} 15 | # Add reporters as children of your supervision tree. 16 | # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} 17 | ] 18 | 19 | Supervisor.init(children, strategy: :one_for_one) 20 | end 21 | 22 | def metrics do 23 | [ 24 | # Phoenix Metrics 25 | summary("phoenix.endpoint.start.system_time", 26 | unit: {:native, :millisecond} 27 | ), 28 | summary("phoenix.endpoint.stop.duration", 29 | unit: {:native, :millisecond} 30 | ), 31 | summary("phoenix.router_dispatch.start.system_time", 32 | tags: [:route], 33 | unit: {:native, :millisecond} 34 | ), 35 | summary("phoenix.router_dispatch.exception.duration", 36 | tags: [:route], 37 | unit: {:native, :millisecond} 38 | ), 39 | summary("phoenix.router_dispatch.stop.duration", 40 | tags: [:route], 41 | unit: {:native, :millisecond} 42 | ), 43 | summary("phoenix.socket_connected.duration", 44 | unit: {:native, :millisecond} 45 | ), 46 | summary("phoenix.channel_joined.duration", 47 | unit: {:native, :millisecond} 48 | ), 49 | summary("phoenix.channel_handled_in.duration", 50 | tags: [:event], 51 | unit: {:native, :millisecond} 52 | ), 53 | 54 | # VM Metrics 55 | summary("vm.memory.total", unit: {:byte, :kilobyte}), 56 | summary("vm.total_run_queue_lengths.total"), 57 | summary("vm.total_run_queue_lengths.cpu"), 58 | summary("vm.total_run_queue_lengths.io") 59 | ] 60 | end 61 | 62 | defp periodic_measurements do 63 | [ 64 | # A module, function and arguments to be invoked periodically. 65 | # This function must call :telemetry.execute/3 and a metric must be added above. 66 | # {ElixirPdfWeb, :count_users, []} 67 | ] 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /lib/rust_reader.ex: -------------------------------------------------------------------------------- 1 | defmodule RustReader do 2 | use Rustler, otp_app: :elixir_pdf, crate: "rustreader" 3 | 4 | # Define the function that will be implemented in Rust 5 | def extract_pdf(_path), do: :erlang.nif_error(:nif_not_loaded) 6 | end 7 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdf.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :elixir_pdf, 7 | version: "0.1.0", 8 | elixir: "~> 1.14", 9 | elixirc_paths: elixirc_paths(Mix.env()), 10 | start_permanent: Mix.env() == :prod, 11 | aliases: aliases(), 12 | deps: deps() 13 | ] 14 | end 15 | 16 | # Configuration for the OTP application. 17 | # 18 | # Type `mix help compile.app` for more information. 19 | def application do 20 | [ 21 | mod: {ElixirPdf.Application, []}, 22 | extra_applications: [:logger, :runtime_tools] 23 | ] 24 | end 25 | 26 | # Specifies which paths to compile per environment. 27 | defp elixirc_paths(:test), do: ["lib", "test/support"] 28 | defp elixirc_paths(_), do: ["lib"] 29 | 30 | # Specifies your project dependencies. 31 | # 32 | # Type `mix help deps` for examples and options. 33 | defp deps do 34 | [ 35 | {:phoenix, "~> 1.7.18"}, 36 | {:phoenix_html, "~> 4.1"}, 37 | {:phoenix_live_reload, "~> 1.2", only: :dev}, 38 | {:phoenix_live_view, "~> 1.0.0"}, 39 | {:floki, ">= 0.30.0", only: :test}, 40 | {:phoenix_live_dashboard, "~> 0.8.3"}, 41 | {:esbuild, "~> 0.8", runtime: Mix.env() == :dev}, 42 | {:tailwind, "~> 0.2", runtime: Mix.env() == :dev}, 43 | {:heroicons, 44 | github: "tailwindlabs/heroicons", 45 | tag: "v2.1.1", 46 | sparse: "optimized", 47 | app: false, 48 | compile: false, 49 | depth: 1}, 50 | {:swoosh, "~> 1.5"}, 51 | {:finch, "~> 0.13"}, 52 | {:telemetry_metrics, "~> 1.0"}, 53 | {:telemetry_poller, "~> 1.0"}, 54 | {:gettext, "~> 0.26"}, 55 | {:jason, "~> 1.2"}, 56 | {:dns_cluster, "~> 0.1.1"}, 57 | {:bandit, "~> 1.5"}, 58 | {:rustler, "~> 0.27.0"} 59 | ] 60 | end 61 | 62 | # Aliases are shortcuts or tasks specific to the current project. 63 | # For example, to install project dependencies and perform other setup tasks, run: 64 | # 65 | # $ mix setup 66 | # 67 | # See the documentation for `Mix` for more info on aliases. 68 | defp aliases do 69 | [ 70 | setup: ["deps.get", "assets.setup", "assets.build"], 71 | "assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"], 72 | "assets.build": ["tailwind elixir_pdf", "esbuild elixir_pdf"], 73 | "assets.deploy": [ 74 | "tailwind elixir_pdf --minify", 75 | "esbuild elixir_pdf --minify", 76 | "phx.digest" 77 | ] 78 | ] 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "bandit": {:hex, :bandit, "1.6.6", "f2019a95261d400579075df5bc15641ba8e446cc4777ede6b4ec19e434c3340d", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "ceb19bf154bc2c07ee0c9addf407d817c48107e36a66351500846fc325451bf9"}, 3 | "castore": {:hex, :castore, "1.0.11", "4bbd584741601eb658007339ea730b082cc61f3554cf2e8f39bf693a11b49073", [:mix], [], "hexpm", "e03990b4db988df56262852f20de0f659871c35154691427a5047f4967a16a62"}, 4 | "dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"}, 5 | "esbuild": {:hex, :esbuild, "0.8.2", "5f379dfa383ef482b738e7771daf238b2d1cfb0222bef9d3b20d4c8f06c7a7ac", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "558a8a08ed78eb820efbfda1de196569d8bfa9b51e8371a1934fbb31345feda7"}, 6 | "expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"}, 7 | "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, 8 | "finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"}, 9 | "floki": {:hex, :floki, "0.37.0", "b83e0280bbc6372f2a403b2848013650b16640cd2470aea6701f0632223d719e", [:mix], [], "hexpm", "516a0c15a69f78c47dc8e0b9b3724b29608aa6619379f91b1ffa47109b5d0dd3"}, 10 | "gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"}, 11 | "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized"]}, 12 | "hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"}, 13 | "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, 14 | "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, 15 | "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, 16 | "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, 17 | "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, 18 | "phoenix": {:hex, :phoenix, "1.7.18", "5310c21443514be44ed93c422e15870aef254cf1b3619e4f91538e7529d2b2e4", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "1797fcc82108442a66f2c77a643a62980f342bfeb63d6c9a515ab8294870004e"}, 19 | "phoenix_html": {:hex, :phoenix_html, "4.2.0", "83a4d351b66f472ebcce242e4ae48af1b781866f00ef0eb34c15030d4e2069ac", [:mix], [], "hexpm", "9713b3f238d07043583a94296cc4bbdceacd3b3a6c74667f4df13971e7866ec8"}, 20 | "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.6", "7b1f0327f54c9eb69845fd09a77accf922f488c549a7e7b8618775eb603a62c7", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "1681ab813ec26ca6915beb3414aa138f298e17721dc6a2bde9e6eb8a62360ff6"}, 21 | "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"}, 22 | "phoenix_live_view": {:hex, :phoenix_live_view, "1.0.2", "e7b1dd68c86326e2c45cc81da41e332cc8aa7228a7161e2c811dcd7f1dd14db1", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8a40265b0cd7d3a35f136dfa3cc048e3b198fc3718763411a78c323a44ebebee"}, 23 | "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, 24 | "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, 25 | "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, 26 | "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, 27 | "rustler": {:hex, :rustler, "0.27.0", "53ffe86586fd1a2ea60ad07f1506962914eb669dba26c23010cf672662ec8d64", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "d7f5ccaec6e7a96f700330898ff2e9d48818e40789fd2951ba41ecf457986e92"}, 28 | "swoosh": {:hex, :swoosh, "1.17.6", "27ff070f96246e35b7105ab1c52b2b689f523a3cb83ed9faadb2f33bd653ccba", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9798f3e72165f40c950f6762c06dab68afcdcf616138fc4a07965c09c250e1e2"}, 29 | "tailwind": {:hex, :tailwind, "0.2.4", "5706ec47182d4e7045901302bf3a333e80f3d1af65c442ba9a9eed152fb26c2e", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "c6e4a82b8727bab593700c998a4d98cf3d8025678bfde059aed71d0000c3e463"}, 30 | "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, 31 | "telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"}, 32 | "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"}, 33 | "thousand_island": {:hex, :thousand_island, "1.3.9", "095db3e2650819443e33237891271943fad3b7f9ba341073947581362582ab5a", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "25ab4c07badadf7f87adb4ab414e0ed374e5f19e72503aa85132caa25776e54f"}, 34 | "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"}, 35 | "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, 36 | "websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"}, 37 | } 38 | -------------------------------------------------------------------------------- /native/rustreader/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.'cfg(target_os = "macos")'] 2 | rustflags = [ 3 | "-C", "link-arg=-undefined", 4 | "-C", "link-arg=dynamic_lookup", 5 | ] 6 | -------------------------------------------------------------------------------- /native/rustreader/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /native/rustreader/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "aes" 22 | version = "0.8.4" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" 25 | dependencies = [ 26 | "cfg-if", 27 | "cipher", 28 | "cpufeatures", 29 | ] 30 | 31 | [[package]] 32 | name = "arbitrary" 33 | version = "1.4.1" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" 36 | dependencies = [ 37 | "derive_arbitrary", 38 | ] 39 | 40 | [[package]] 41 | name = "atomic-waker" 42 | version = "1.1.2" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 45 | 46 | [[package]] 47 | name = "autocfg" 48 | version = "1.4.0" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 51 | 52 | [[package]] 53 | name = "backtrace" 54 | version = "0.3.74" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 57 | dependencies = [ 58 | "addr2line", 59 | "cfg-if", 60 | "libc", 61 | "miniz_oxide", 62 | "object", 63 | "rustc-demangle", 64 | "windows-targets 0.52.6", 65 | ] 66 | 67 | [[package]] 68 | name = "base64" 69 | version = "0.22.1" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 72 | 73 | [[package]] 74 | name = "bitflags" 75 | version = "2.8.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 78 | 79 | [[package]] 80 | name = "block-buffer" 81 | version = "0.10.4" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 84 | dependencies = [ 85 | "generic-array", 86 | ] 87 | 88 | [[package]] 89 | name = "bumpalo" 90 | version = "3.16.0" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 93 | 94 | [[package]] 95 | name = "bytemuck" 96 | version = "1.21.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" 99 | 100 | [[package]] 101 | name = "byteorder" 102 | version = "1.5.0" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 105 | 106 | [[package]] 107 | name = "bytes" 108 | version = "1.9.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 111 | 112 | [[package]] 113 | name = "bzip2" 114 | version = "0.4.4" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" 117 | dependencies = [ 118 | "bzip2-sys", 119 | "libc", 120 | ] 121 | 122 | [[package]] 123 | name = "bzip2-sys" 124 | version = "0.1.11+1.0.8" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" 127 | dependencies = [ 128 | "cc", 129 | "libc", 130 | "pkg-config", 131 | ] 132 | 133 | [[package]] 134 | name = "cc" 135 | version = "1.2.10" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" 138 | dependencies = [ 139 | "jobserver", 140 | "libc", 141 | "shlex", 142 | ] 143 | 144 | [[package]] 145 | name = "cesu8" 146 | version = "1.1.0" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" 149 | 150 | [[package]] 151 | name = "cfg-if" 152 | version = "1.0.0" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 155 | 156 | [[package]] 157 | name = "cipher" 158 | version = "0.4.4" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" 161 | dependencies = [ 162 | "crypto-common", 163 | "inout", 164 | ] 165 | 166 | [[package]] 167 | name = "combine" 168 | version = "4.6.7" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" 171 | dependencies = [ 172 | "bytes", 173 | "memchr", 174 | ] 175 | 176 | [[package]] 177 | name = "constant_time_eq" 178 | version = "0.3.1" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" 181 | 182 | [[package]] 183 | name = "core-foundation" 184 | version = "0.9.4" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 187 | dependencies = [ 188 | "core-foundation-sys", 189 | "libc", 190 | ] 191 | 192 | [[package]] 193 | name = "core-foundation-sys" 194 | version = "0.8.7" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 197 | 198 | [[package]] 199 | name = "cpufeatures" 200 | version = "0.2.17" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 203 | dependencies = [ 204 | "libc", 205 | ] 206 | 207 | [[package]] 208 | name = "crc" 209 | version = "3.2.1" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" 212 | dependencies = [ 213 | "crc-catalog", 214 | ] 215 | 216 | [[package]] 217 | name = "crc-catalog" 218 | version = "2.4.0" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 221 | 222 | [[package]] 223 | name = "crc32fast" 224 | version = "1.4.2" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 227 | dependencies = [ 228 | "cfg-if", 229 | ] 230 | 231 | [[package]] 232 | name = "crossbeam-utils" 233 | version = "0.8.21" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 236 | 237 | [[package]] 238 | name = "crypto-common" 239 | version = "0.1.6" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 242 | dependencies = [ 243 | "generic-array", 244 | "typenum", 245 | ] 246 | 247 | [[package]] 248 | name = "deflate64" 249 | version = "0.1.9" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" 252 | 253 | [[package]] 254 | name = "deranged" 255 | version = "0.3.11" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 258 | dependencies = [ 259 | "powerfmt", 260 | ] 261 | 262 | [[package]] 263 | name = "derive_arbitrary" 264 | version = "1.4.1" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" 267 | dependencies = [ 268 | "proc-macro2", 269 | "quote", 270 | "syn", 271 | ] 272 | 273 | [[package]] 274 | name = "digest" 275 | version = "0.10.7" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 278 | dependencies = [ 279 | "block-buffer", 280 | "crypto-common", 281 | "subtle", 282 | ] 283 | 284 | [[package]] 285 | name = "displaydoc" 286 | version = "0.2.5" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 289 | dependencies = [ 290 | "proc-macro2", 291 | "quote", 292 | "syn", 293 | ] 294 | 295 | [[package]] 296 | name = "encoding_rs" 297 | version = "0.8.35" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 300 | dependencies = [ 301 | "cfg-if", 302 | ] 303 | 304 | [[package]] 305 | name = "equivalent" 306 | version = "1.0.1" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 309 | 310 | [[package]] 311 | name = "errno" 312 | version = "0.3.10" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 315 | dependencies = [ 316 | "libc", 317 | "windows-sys 0.59.0", 318 | ] 319 | 320 | [[package]] 321 | name = "extractous" 322 | version = "0.2.0" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "cfc454a41e38531aa560abc8d4c3b4c02b94da32013720af3bc9c4e171025501" 325 | dependencies = [ 326 | "bytemuck", 327 | "flate2", 328 | "fs_extra", 329 | "jni", 330 | "libc", 331 | "reqwest", 332 | "strum", 333 | "strum_macros", 334 | "tar", 335 | "thiserror 1.0.69", 336 | "zip", 337 | ] 338 | 339 | [[package]] 340 | name = "fastrand" 341 | version = "2.3.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 344 | 345 | [[package]] 346 | name = "filetime" 347 | version = "0.2.25" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" 350 | dependencies = [ 351 | "cfg-if", 352 | "libc", 353 | "libredox", 354 | "windows-sys 0.59.0", 355 | ] 356 | 357 | [[package]] 358 | name = "flate2" 359 | version = "1.0.35" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" 362 | dependencies = [ 363 | "crc32fast", 364 | "miniz_oxide", 365 | ] 366 | 367 | [[package]] 368 | name = "fnv" 369 | version = "1.0.7" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 372 | 373 | [[package]] 374 | name = "foreign-types" 375 | version = "0.3.2" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 378 | dependencies = [ 379 | "foreign-types-shared", 380 | ] 381 | 382 | [[package]] 383 | name = "foreign-types-shared" 384 | version = "0.1.1" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 387 | 388 | [[package]] 389 | name = "form_urlencoded" 390 | version = "1.2.1" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 393 | dependencies = [ 394 | "percent-encoding", 395 | ] 396 | 397 | [[package]] 398 | name = "fs_extra" 399 | version = "1.3.0" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" 402 | 403 | [[package]] 404 | name = "futures-channel" 405 | version = "0.3.31" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 408 | dependencies = [ 409 | "futures-core", 410 | "futures-sink", 411 | ] 412 | 413 | [[package]] 414 | name = "futures-core" 415 | version = "0.3.31" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 418 | 419 | [[package]] 420 | name = "futures-io" 421 | version = "0.3.31" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 424 | 425 | [[package]] 426 | name = "futures-sink" 427 | version = "0.3.31" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 430 | 431 | [[package]] 432 | name = "futures-task" 433 | version = "0.3.31" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 436 | 437 | [[package]] 438 | name = "futures-util" 439 | version = "0.3.31" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 442 | dependencies = [ 443 | "futures-core", 444 | "futures-io", 445 | "futures-sink", 446 | "futures-task", 447 | "memchr", 448 | "pin-project-lite", 449 | "pin-utils", 450 | "slab", 451 | ] 452 | 453 | [[package]] 454 | name = "generic-array" 455 | version = "0.14.7" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 458 | dependencies = [ 459 | "typenum", 460 | "version_check", 461 | ] 462 | 463 | [[package]] 464 | name = "getrandom" 465 | version = "0.2.15" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 468 | dependencies = [ 469 | "cfg-if", 470 | "libc", 471 | "wasi", 472 | ] 473 | 474 | [[package]] 475 | name = "gimli" 476 | version = "0.31.1" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 479 | 480 | [[package]] 481 | name = "glob" 482 | version = "0.3.2" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" 485 | 486 | [[package]] 487 | name = "h2" 488 | version = "0.4.7" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" 491 | dependencies = [ 492 | "atomic-waker", 493 | "bytes", 494 | "fnv", 495 | "futures-core", 496 | "futures-sink", 497 | "http", 498 | "indexmap", 499 | "slab", 500 | "tokio", 501 | "tokio-util", 502 | "tracing", 503 | ] 504 | 505 | [[package]] 506 | name = "hashbrown" 507 | version = "0.15.2" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 510 | 511 | [[package]] 512 | name = "heck" 513 | version = "0.5.0" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 516 | 517 | [[package]] 518 | name = "hmac" 519 | version = "0.12.1" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 522 | dependencies = [ 523 | "digest", 524 | ] 525 | 526 | [[package]] 527 | name = "http" 528 | version = "1.2.0" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" 531 | dependencies = [ 532 | "bytes", 533 | "fnv", 534 | "itoa", 535 | ] 536 | 537 | [[package]] 538 | name = "http-body" 539 | version = "1.0.1" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 542 | dependencies = [ 543 | "bytes", 544 | "http", 545 | ] 546 | 547 | [[package]] 548 | name = "http-body-util" 549 | version = "0.1.2" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 552 | dependencies = [ 553 | "bytes", 554 | "futures-util", 555 | "http", 556 | "http-body", 557 | "pin-project-lite", 558 | ] 559 | 560 | [[package]] 561 | name = "httparse" 562 | version = "1.10.0" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" 565 | 566 | [[package]] 567 | name = "hyper" 568 | version = "1.6.0" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 571 | dependencies = [ 572 | "bytes", 573 | "futures-channel", 574 | "futures-util", 575 | "h2", 576 | "http", 577 | "http-body", 578 | "httparse", 579 | "itoa", 580 | "pin-project-lite", 581 | "smallvec", 582 | "tokio", 583 | "want", 584 | ] 585 | 586 | [[package]] 587 | name = "hyper-rustls" 588 | version = "0.27.5" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" 591 | dependencies = [ 592 | "futures-util", 593 | "http", 594 | "hyper", 595 | "hyper-util", 596 | "rustls", 597 | "rustls-pki-types", 598 | "tokio", 599 | "tokio-rustls", 600 | "tower-service", 601 | ] 602 | 603 | [[package]] 604 | name = "hyper-tls" 605 | version = "0.6.0" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 608 | dependencies = [ 609 | "bytes", 610 | "http-body-util", 611 | "hyper", 612 | "hyper-util", 613 | "native-tls", 614 | "tokio", 615 | "tokio-native-tls", 616 | "tower-service", 617 | ] 618 | 619 | [[package]] 620 | name = "hyper-util" 621 | version = "0.1.10" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" 624 | dependencies = [ 625 | "bytes", 626 | "futures-channel", 627 | "futures-util", 628 | "http", 629 | "http-body", 630 | "hyper", 631 | "pin-project-lite", 632 | "socket2", 633 | "tokio", 634 | "tower-service", 635 | "tracing", 636 | ] 637 | 638 | [[package]] 639 | name = "icu_collections" 640 | version = "1.5.0" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 643 | dependencies = [ 644 | "displaydoc", 645 | "yoke", 646 | "zerofrom", 647 | "zerovec", 648 | ] 649 | 650 | [[package]] 651 | name = "icu_locid" 652 | version = "1.5.0" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 655 | dependencies = [ 656 | "displaydoc", 657 | "litemap", 658 | "tinystr", 659 | "writeable", 660 | "zerovec", 661 | ] 662 | 663 | [[package]] 664 | name = "icu_locid_transform" 665 | version = "1.5.0" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 668 | dependencies = [ 669 | "displaydoc", 670 | "icu_locid", 671 | "icu_locid_transform_data", 672 | "icu_provider", 673 | "tinystr", 674 | "zerovec", 675 | ] 676 | 677 | [[package]] 678 | name = "icu_locid_transform_data" 679 | version = "1.5.0" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 682 | 683 | [[package]] 684 | name = "icu_normalizer" 685 | version = "1.5.0" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 688 | dependencies = [ 689 | "displaydoc", 690 | "icu_collections", 691 | "icu_normalizer_data", 692 | "icu_properties", 693 | "icu_provider", 694 | "smallvec", 695 | "utf16_iter", 696 | "utf8_iter", 697 | "write16", 698 | "zerovec", 699 | ] 700 | 701 | [[package]] 702 | name = "icu_normalizer_data" 703 | version = "1.5.0" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 706 | 707 | [[package]] 708 | name = "icu_properties" 709 | version = "1.5.1" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 712 | dependencies = [ 713 | "displaydoc", 714 | "icu_collections", 715 | "icu_locid_transform", 716 | "icu_properties_data", 717 | "icu_provider", 718 | "tinystr", 719 | "zerovec", 720 | ] 721 | 722 | [[package]] 723 | name = "icu_properties_data" 724 | version = "1.5.0" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 727 | 728 | [[package]] 729 | name = "icu_provider" 730 | version = "1.5.0" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 733 | dependencies = [ 734 | "displaydoc", 735 | "icu_locid", 736 | "icu_provider_macros", 737 | "stable_deref_trait", 738 | "tinystr", 739 | "writeable", 740 | "yoke", 741 | "zerofrom", 742 | "zerovec", 743 | ] 744 | 745 | [[package]] 746 | name = "icu_provider_macros" 747 | version = "1.5.0" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 750 | dependencies = [ 751 | "proc-macro2", 752 | "quote", 753 | "syn", 754 | ] 755 | 756 | [[package]] 757 | name = "idna" 758 | version = "1.0.3" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 761 | dependencies = [ 762 | "idna_adapter", 763 | "smallvec", 764 | "utf8_iter", 765 | ] 766 | 767 | [[package]] 768 | name = "idna_adapter" 769 | version = "1.2.0" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 772 | dependencies = [ 773 | "icu_normalizer", 774 | "icu_properties", 775 | ] 776 | 777 | [[package]] 778 | name = "indexmap" 779 | version = "2.7.1" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" 782 | dependencies = [ 783 | "equivalent", 784 | "hashbrown", 785 | ] 786 | 787 | [[package]] 788 | name = "inout" 789 | version = "0.1.3" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" 792 | dependencies = [ 793 | "generic-array", 794 | ] 795 | 796 | [[package]] 797 | name = "inventory" 798 | version = "0.3.17" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "3b31349d02fe60f80bbbab1a9402364cad7460626d6030494b08ac4a2075bf81" 801 | dependencies = [ 802 | "rustversion", 803 | ] 804 | 805 | [[package]] 806 | name = "ipnet" 807 | version = "2.11.0" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 810 | 811 | [[package]] 812 | name = "itoa" 813 | version = "1.0.14" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 816 | 817 | [[package]] 818 | name = "java-locator" 819 | version = "0.1.8" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "6f25f28894af6a5dd349ed5ec46e178654e75f62edb6717ac74007102a57deb5" 822 | dependencies = [ 823 | "glob", 824 | ] 825 | 826 | [[package]] 827 | name = "jni" 828 | version = "0.21.1" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" 831 | dependencies = [ 832 | "cesu8", 833 | "cfg-if", 834 | "combine", 835 | "java-locator", 836 | "jni-sys", 837 | "libloading 0.7.4", 838 | "log", 839 | "thiserror 1.0.69", 840 | "walkdir", 841 | "windows-sys 0.45.0", 842 | ] 843 | 844 | [[package]] 845 | name = "jni-sys" 846 | version = "0.3.0" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" 849 | 850 | [[package]] 851 | name = "jobserver" 852 | version = "0.1.32" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" 855 | dependencies = [ 856 | "libc", 857 | ] 858 | 859 | [[package]] 860 | name = "js-sys" 861 | version = "0.3.77" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 864 | dependencies = [ 865 | "once_cell", 866 | "wasm-bindgen", 867 | ] 868 | 869 | [[package]] 870 | name = "libc" 871 | version = "0.2.169" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 874 | 875 | [[package]] 876 | name = "libloading" 877 | version = "0.7.4" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" 880 | dependencies = [ 881 | "cfg-if", 882 | "winapi", 883 | ] 884 | 885 | [[package]] 886 | name = "libloading" 887 | version = "0.8.6" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" 890 | dependencies = [ 891 | "cfg-if", 892 | "windows-targets 0.52.6", 893 | ] 894 | 895 | [[package]] 896 | name = "libredox" 897 | version = "0.1.3" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 900 | dependencies = [ 901 | "bitflags", 902 | "libc", 903 | "redox_syscall", 904 | ] 905 | 906 | [[package]] 907 | name = "linux-raw-sys" 908 | version = "0.4.15" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 911 | 912 | [[package]] 913 | name = "litemap" 914 | version = "0.7.4" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 917 | 918 | [[package]] 919 | name = "lockfree-object-pool" 920 | version = "0.1.6" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" 923 | 924 | [[package]] 925 | name = "log" 926 | version = "0.4.25" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" 929 | 930 | [[package]] 931 | name = "lzma-rs" 932 | version = "0.3.0" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" 935 | dependencies = [ 936 | "byteorder", 937 | "crc", 938 | ] 939 | 940 | [[package]] 941 | name = "memchr" 942 | version = "2.7.4" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 945 | 946 | [[package]] 947 | name = "mime" 948 | version = "0.3.17" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 951 | 952 | [[package]] 953 | name = "miniz_oxide" 954 | version = "0.8.3" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" 957 | dependencies = [ 958 | "adler2", 959 | ] 960 | 961 | [[package]] 962 | name = "mio" 963 | version = "1.0.3" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 966 | dependencies = [ 967 | "libc", 968 | "wasi", 969 | "windows-sys 0.52.0", 970 | ] 971 | 972 | [[package]] 973 | name = "native-tls" 974 | version = "0.2.13" 975 | source = "registry+https://github.com/rust-lang/crates.io-index" 976 | checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" 977 | dependencies = [ 978 | "libc", 979 | "log", 980 | "openssl", 981 | "openssl-probe", 982 | "openssl-sys", 983 | "schannel", 984 | "security-framework", 985 | "security-framework-sys", 986 | "tempfile", 987 | ] 988 | 989 | [[package]] 990 | name = "num-conv" 991 | version = "0.1.0" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 994 | 995 | [[package]] 996 | name = "object" 997 | version = "0.36.7" 998 | source = "registry+https://github.com/rust-lang/crates.io-index" 999 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 1000 | dependencies = [ 1001 | "memchr", 1002 | ] 1003 | 1004 | [[package]] 1005 | name = "once_cell" 1006 | version = "1.20.2" 1007 | source = "registry+https://github.com/rust-lang/crates.io-index" 1008 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 1009 | 1010 | [[package]] 1011 | name = "openssl" 1012 | version = "0.10.69" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e" 1015 | dependencies = [ 1016 | "bitflags", 1017 | "cfg-if", 1018 | "foreign-types", 1019 | "libc", 1020 | "once_cell", 1021 | "openssl-macros", 1022 | "openssl-sys", 1023 | ] 1024 | 1025 | [[package]] 1026 | name = "openssl-macros" 1027 | version = "0.1.1" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1030 | dependencies = [ 1031 | "proc-macro2", 1032 | "quote", 1033 | "syn", 1034 | ] 1035 | 1036 | [[package]] 1037 | name = "openssl-probe" 1038 | version = "0.1.6" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 1041 | 1042 | [[package]] 1043 | name = "openssl-sys" 1044 | version = "0.9.104" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" 1047 | dependencies = [ 1048 | "cc", 1049 | "libc", 1050 | "pkg-config", 1051 | "vcpkg", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "pbkdf2" 1056 | version = "0.12.2" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" 1059 | dependencies = [ 1060 | "digest", 1061 | "hmac", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "percent-encoding" 1066 | version = "2.3.1" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1069 | 1070 | [[package]] 1071 | name = "pin-project-lite" 1072 | version = "0.2.16" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1075 | 1076 | [[package]] 1077 | name = "pin-utils" 1078 | version = "0.1.0" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1081 | 1082 | [[package]] 1083 | name = "pkg-config" 1084 | version = "0.3.31" 1085 | source = "registry+https://github.com/rust-lang/crates.io-index" 1086 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 1087 | 1088 | [[package]] 1089 | name = "powerfmt" 1090 | version = "0.2.0" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1093 | 1094 | [[package]] 1095 | name = "ppv-lite86" 1096 | version = "0.2.20" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 1099 | dependencies = [ 1100 | "zerocopy", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "proc-macro2" 1105 | version = "1.0.93" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 1108 | dependencies = [ 1109 | "unicode-ident", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "quote" 1114 | version = "1.0.38" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 1117 | dependencies = [ 1118 | "proc-macro2", 1119 | ] 1120 | 1121 | [[package]] 1122 | name = "rand" 1123 | version = "0.8.5" 1124 | source = "registry+https://github.com/rust-lang/crates.io-index" 1125 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1126 | dependencies = [ 1127 | "libc", 1128 | "rand_chacha", 1129 | "rand_core", 1130 | ] 1131 | 1132 | [[package]] 1133 | name = "rand_chacha" 1134 | version = "0.3.1" 1135 | source = "registry+https://github.com/rust-lang/crates.io-index" 1136 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1137 | dependencies = [ 1138 | "ppv-lite86", 1139 | "rand_core", 1140 | ] 1141 | 1142 | [[package]] 1143 | name = "rand_core" 1144 | version = "0.6.4" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1147 | dependencies = [ 1148 | "getrandom", 1149 | ] 1150 | 1151 | [[package]] 1152 | name = "redox_syscall" 1153 | version = "0.5.8" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 1156 | dependencies = [ 1157 | "bitflags", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "regex-lite" 1162 | version = "0.1.6" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" 1165 | 1166 | [[package]] 1167 | name = "reqwest" 1168 | version = "0.12.12" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" 1171 | dependencies = [ 1172 | "base64", 1173 | "bytes", 1174 | "encoding_rs", 1175 | "futures-channel", 1176 | "futures-core", 1177 | "futures-util", 1178 | "h2", 1179 | "http", 1180 | "http-body", 1181 | "http-body-util", 1182 | "hyper", 1183 | "hyper-rustls", 1184 | "hyper-tls", 1185 | "hyper-util", 1186 | "ipnet", 1187 | "js-sys", 1188 | "log", 1189 | "mime", 1190 | "native-tls", 1191 | "once_cell", 1192 | "percent-encoding", 1193 | "pin-project-lite", 1194 | "rustls-pemfile", 1195 | "serde", 1196 | "serde_json", 1197 | "serde_urlencoded", 1198 | "sync_wrapper", 1199 | "system-configuration", 1200 | "tokio", 1201 | "tokio-native-tls", 1202 | "tower", 1203 | "tower-service", 1204 | "url", 1205 | "wasm-bindgen", 1206 | "wasm-bindgen-futures", 1207 | "web-sys", 1208 | "windows-registry", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "ring" 1213 | version = "0.17.8" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1216 | dependencies = [ 1217 | "cc", 1218 | "cfg-if", 1219 | "getrandom", 1220 | "libc", 1221 | "spin", 1222 | "untrusted", 1223 | "windows-sys 0.52.0", 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "rustc-demangle" 1228 | version = "0.1.24" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1231 | 1232 | [[package]] 1233 | name = "rustix" 1234 | version = "0.38.44" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 1237 | dependencies = [ 1238 | "bitflags", 1239 | "errno", 1240 | "libc", 1241 | "linux-raw-sys", 1242 | "windows-sys 0.59.0", 1243 | ] 1244 | 1245 | [[package]] 1246 | name = "rustler" 1247 | version = "0.36.0" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "1f7b219d7473cf473409665a4898d66688b34736e51bb5791098b0d3390e4c98" 1250 | dependencies = [ 1251 | "inventory", 1252 | "libloading 0.8.6", 1253 | "regex-lite", 1254 | "rustler_codegen", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "rustler_codegen" 1259 | version = "0.36.0" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "743ec5267bd5f18fd88d89f7e729c0f43b97d9c2539959915fa1f234300bb621" 1262 | dependencies = [ 1263 | "heck", 1264 | "inventory", 1265 | "proc-macro2", 1266 | "quote", 1267 | "syn", 1268 | ] 1269 | 1270 | [[package]] 1271 | name = "rustls" 1272 | version = "0.23.21" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" 1275 | dependencies = [ 1276 | "once_cell", 1277 | "rustls-pki-types", 1278 | "rustls-webpki", 1279 | "subtle", 1280 | "zeroize", 1281 | ] 1282 | 1283 | [[package]] 1284 | name = "rustls-pemfile" 1285 | version = "2.2.0" 1286 | source = "registry+https://github.com/rust-lang/crates.io-index" 1287 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 1288 | dependencies = [ 1289 | "rustls-pki-types", 1290 | ] 1291 | 1292 | [[package]] 1293 | name = "rustls-pki-types" 1294 | version = "1.11.0" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" 1297 | 1298 | [[package]] 1299 | name = "rustls-webpki" 1300 | version = "0.102.8" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 1303 | dependencies = [ 1304 | "ring", 1305 | "rustls-pki-types", 1306 | "untrusted", 1307 | ] 1308 | 1309 | [[package]] 1310 | name = "rustreader" 1311 | version = "0.1.0" 1312 | dependencies = [ 1313 | "extractous", 1314 | "rustler", 1315 | ] 1316 | 1317 | [[package]] 1318 | name = "rustversion" 1319 | version = "1.0.19" 1320 | source = "registry+https://github.com/rust-lang/crates.io-index" 1321 | checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" 1322 | 1323 | [[package]] 1324 | name = "ryu" 1325 | version = "1.0.19" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" 1328 | 1329 | [[package]] 1330 | name = "same-file" 1331 | version = "1.0.6" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1334 | dependencies = [ 1335 | "winapi-util", 1336 | ] 1337 | 1338 | [[package]] 1339 | name = "schannel" 1340 | version = "0.1.27" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1343 | dependencies = [ 1344 | "windows-sys 0.59.0", 1345 | ] 1346 | 1347 | [[package]] 1348 | name = "security-framework" 1349 | version = "2.11.1" 1350 | source = "registry+https://github.com/rust-lang/crates.io-index" 1351 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1352 | dependencies = [ 1353 | "bitflags", 1354 | "core-foundation", 1355 | "core-foundation-sys", 1356 | "libc", 1357 | "security-framework-sys", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "security-framework-sys" 1362 | version = "2.14.0" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 1365 | dependencies = [ 1366 | "core-foundation-sys", 1367 | "libc", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "serde" 1372 | version = "1.0.217" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 1375 | dependencies = [ 1376 | "serde_derive", 1377 | ] 1378 | 1379 | [[package]] 1380 | name = "serde_derive" 1381 | version = "1.0.217" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 1384 | dependencies = [ 1385 | "proc-macro2", 1386 | "quote", 1387 | "syn", 1388 | ] 1389 | 1390 | [[package]] 1391 | name = "serde_json" 1392 | version = "1.0.137" 1393 | source = "registry+https://github.com/rust-lang/crates.io-index" 1394 | checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" 1395 | dependencies = [ 1396 | "itoa", 1397 | "memchr", 1398 | "ryu", 1399 | "serde", 1400 | ] 1401 | 1402 | [[package]] 1403 | name = "serde_urlencoded" 1404 | version = "0.7.1" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1407 | dependencies = [ 1408 | "form_urlencoded", 1409 | "itoa", 1410 | "ryu", 1411 | "serde", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "sha1" 1416 | version = "0.10.6" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1419 | dependencies = [ 1420 | "cfg-if", 1421 | "cpufeatures", 1422 | "digest", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "shlex" 1427 | version = "1.3.0" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1430 | 1431 | [[package]] 1432 | name = "simd-adler32" 1433 | version = "0.3.7" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 1436 | 1437 | [[package]] 1438 | name = "slab" 1439 | version = "0.4.9" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1442 | dependencies = [ 1443 | "autocfg", 1444 | ] 1445 | 1446 | [[package]] 1447 | name = "smallvec" 1448 | version = "1.13.2" 1449 | source = "registry+https://github.com/rust-lang/crates.io-index" 1450 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1451 | 1452 | [[package]] 1453 | name = "socket2" 1454 | version = "0.5.8" 1455 | source = "registry+https://github.com/rust-lang/crates.io-index" 1456 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 1457 | dependencies = [ 1458 | "libc", 1459 | "windows-sys 0.52.0", 1460 | ] 1461 | 1462 | [[package]] 1463 | name = "spin" 1464 | version = "0.9.8" 1465 | source = "registry+https://github.com/rust-lang/crates.io-index" 1466 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1467 | 1468 | [[package]] 1469 | name = "stable_deref_trait" 1470 | version = "1.2.0" 1471 | source = "registry+https://github.com/rust-lang/crates.io-index" 1472 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1473 | 1474 | [[package]] 1475 | name = "strum" 1476 | version = "0.26.3" 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" 1478 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 1479 | 1480 | [[package]] 1481 | name = "strum_macros" 1482 | version = "0.26.4" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 1485 | dependencies = [ 1486 | "heck", 1487 | "proc-macro2", 1488 | "quote", 1489 | "rustversion", 1490 | "syn", 1491 | ] 1492 | 1493 | [[package]] 1494 | name = "subtle" 1495 | version = "2.6.1" 1496 | source = "registry+https://github.com/rust-lang/crates.io-index" 1497 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1498 | 1499 | [[package]] 1500 | name = "syn" 1501 | version = "2.0.96" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 1504 | dependencies = [ 1505 | "proc-macro2", 1506 | "quote", 1507 | "unicode-ident", 1508 | ] 1509 | 1510 | [[package]] 1511 | name = "sync_wrapper" 1512 | version = "1.0.2" 1513 | source = "registry+https://github.com/rust-lang/crates.io-index" 1514 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1515 | dependencies = [ 1516 | "futures-core", 1517 | ] 1518 | 1519 | [[package]] 1520 | name = "synstructure" 1521 | version = "0.13.1" 1522 | source = "registry+https://github.com/rust-lang/crates.io-index" 1523 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1524 | dependencies = [ 1525 | "proc-macro2", 1526 | "quote", 1527 | "syn", 1528 | ] 1529 | 1530 | [[package]] 1531 | name = "system-configuration" 1532 | version = "0.6.1" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 1535 | dependencies = [ 1536 | "bitflags", 1537 | "core-foundation", 1538 | "system-configuration-sys", 1539 | ] 1540 | 1541 | [[package]] 1542 | name = "system-configuration-sys" 1543 | version = "0.6.0" 1544 | source = "registry+https://github.com/rust-lang/crates.io-index" 1545 | checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 1546 | dependencies = [ 1547 | "core-foundation-sys", 1548 | "libc", 1549 | ] 1550 | 1551 | [[package]] 1552 | name = "tar" 1553 | version = "0.4.43" 1554 | source = "registry+https://github.com/rust-lang/crates.io-index" 1555 | checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" 1556 | dependencies = [ 1557 | "filetime", 1558 | "libc", 1559 | "xattr", 1560 | ] 1561 | 1562 | [[package]] 1563 | name = "tempfile" 1564 | version = "3.15.0" 1565 | source = "registry+https://github.com/rust-lang/crates.io-index" 1566 | checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" 1567 | dependencies = [ 1568 | "cfg-if", 1569 | "fastrand", 1570 | "getrandom", 1571 | "once_cell", 1572 | "rustix", 1573 | "windows-sys 0.59.0", 1574 | ] 1575 | 1576 | [[package]] 1577 | name = "thiserror" 1578 | version = "1.0.69" 1579 | source = "registry+https://github.com/rust-lang/crates.io-index" 1580 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1581 | dependencies = [ 1582 | "thiserror-impl 1.0.69", 1583 | ] 1584 | 1585 | [[package]] 1586 | name = "thiserror" 1587 | version = "2.0.11" 1588 | source = "registry+https://github.com/rust-lang/crates.io-index" 1589 | checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" 1590 | dependencies = [ 1591 | "thiserror-impl 2.0.11", 1592 | ] 1593 | 1594 | [[package]] 1595 | name = "thiserror-impl" 1596 | version = "1.0.69" 1597 | source = "registry+https://github.com/rust-lang/crates.io-index" 1598 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1599 | dependencies = [ 1600 | "proc-macro2", 1601 | "quote", 1602 | "syn", 1603 | ] 1604 | 1605 | [[package]] 1606 | name = "thiserror-impl" 1607 | version = "2.0.11" 1608 | source = "registry+https://github.com/rust-lang/crates.io-index" 1609 | checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" 1610 | dependencies = [ 1611 | "proc-macro2", 1612 | "quote", 1613 | "syn", 1614 | ] 1615 | 1616 | [[package]] 1617 | name = "time" 1618 | version = "0.3.37" 1619 | source = "registry+https://github.com/rust-lang/crates.io-index" 1620 | checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" 1621 | dependencies = [ 1622 | "deranged", 1623 | "num-conv", 1624 | "powerfmt", 1625 | "serde", 1626 | "time-core", 1627 | ] 1628 | 1629 | [[package]] 1630 | name = "time-core" 1631 | version = "0.1.2" 1632 | source = "registry+https://github.com/rust-lang/crates.io-index" 1633 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 1634 | 1635 | [[package]] 1636 | name = "tinystr" 1637 | version = "0.7.6" 1638 | source = "registry+https://github.com/rust-lang/crates.io-index" 1639 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 1640 | dependencies = [ 1641 | "displaydoc", 1642 | "zerovec", 1643 | ] 1644 | 1645 | [[package]] 1646 | name = "tokio" 1647 | version = "1.43.0" 1648 | source = "registry+https://github.com/rust-lang/crates.io-index" 1649 | checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" 1650 | dependencies = [ 1651 | "backtrace", 1652 | "bytes", 1653 | "libc", 1654 | "mio", 1655 | "pin-project-lite", 1656 | "socket2", 1657 | "windows-sys 0.52.0", 1658 | ] 1659 | 1660 | [[package]] 1661 | name = "tokio-native-tls" 1662 | version = "0.3.1" 1663 | source = "registry+https://github.com/rust-lang/crates.io-index" 1664 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1665 | dependencies = [ 1666 | "native-tls", 1667 | "tokio", 1668 | ] 1669 | 1670 | [[package]] 1671 | name = "tokio-rustls" 1672 | version = "0.26.1" 1673 | source = "registry+https://github.com/rust-lang/crates.io-index" 1674 | checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" 1675 | dependencies = [ 1676 | "rustls", 1677 | "tokio", 1678 | ] 1679 | 1680 | [[package]] 1681 | name = "tokio-util" 1682 | version = "0.7.13" 1683 | source = "registry+https://github.com/rust-lang/crates.io-index" 1684 | checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" 1685 | dependencies = [ 1686 | "bytes", 1687 | "futures-core", 1688 | "futures-sink", 1689 | "pin-project-lite", 1690 | "tokio", 1691 | ] 1692 | 1693 | [[package]] 1694 | name = "tower" 1695 | version = "0.5.2" 1696 | source = "registry+https://github.com/rust-lang/crates.io-index" 1697 | checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 1698 | dependencies = [ 1699 | "futures-core", 1700 | "futures-util", 1701 | "pin-project-lite", 1702 | "sync_wrapper", 1703 | "tokio", 1704 | "tower-layer", 1705 | "tower-service", 1706 | ] 1707 | 1708 | [[package]] 1709 | name = "tower-layer" 1710 | version = "0.3.3" 1711 | source = "registry+https://github.com/rust-lang/crates.io-index" 1712 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1713 | 1714 | [[package]] 1715 | name = "tower-service" 1716 | version = "0.3.3" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1719 | 1720 | [[package]] 1721 | name = "tracing" 1722 | version = "0.1.41" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1725 | dependencies = [ 1726 | "pin-project-lite", 1727 | "tracing-core", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "tracing-core" 1732 | version = "0.1.33" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1735 | dependencies = [ 1736 | "once_cell", 1737 | ] 1738 | 1739 | [[package]] 1740 | name = "try-lock" 1741 | version = "0.2.5" 1742 | source = "registry+https://github.com/rust-lang/crates.io-index" 1743 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1744 | 1745 | [[package]] 1746 | name = "typenum" 1747 | version = "1.17.0" 1748 | source = "registry+https://github.com/rust-lang/crates.io-index" 1749 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1750 | 1751 | [[package]] 1752 | name = "unicode-ident" 1753 | version = "1.0.16" 1754 | source = "registry+https://github.com/rust-lang/crates.io-index" 1755 | checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" 1756 | 1757 | [[package]] 1758 | name = "untrusted" 1759 | version = "0.9.0" 1760 | source = "registry+https://github.com/rust-lang/crates.io-index" 1761 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1762 | 1763 | [[package]] 1764 | name = "url" 1765 | version = "2.5.4" 1766 | source = "registry+https://github.com/rust-lang/crates.io-index" 1767 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1768 | dependencies = [ 1769 | "form_urlencoded", 1770 | "idna", 1771 | "percent-encoding", 1772 | ] 1773 | 1774 | [[package]] 1775 | name = "utf16_iter" 1776 | version = "1.0.5" 1777 | source = "registry+https://github.com/rust-lang/crates.io-index" 1778 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 1779 | 1780 | [[package]] 1781 | name = "utf8_iter" 1782 | version = "1.0.4" 1783 | source = "registry+https://github.com/rust-lang/crates.io-index" 1784 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1785 | 1786 | [[package]] 1787 | name = "vcpkg" 1788 | version = "0.2.15" 1789 | source = "registry+https://github.com/rust-lang/crates.io-index" 1790 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1791 | 1792 | [[package]] 1793 | name = "version_check" 1794 | version = "0.9.5" 1795 | source = "registry+https://github.com/rust-lang/crates.io-index" 1796 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1797 | 1798 | [[package]] 1799 | name = "walkdir" 1800 | version = "2.5.0" 1801 | source = "registry+https://github.com/rust-lang/crates.io-index" 1802 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 1803 | dependencies = [ 1804 | "same-file", 1805 | "winapi-util", 1806 | ] 1807 | 1808 | [[package]] 1809 | name = "want" 1810 | version = "0.3.1" 1811 | source = "registry+https://github.com/rust-lang/crates.io-index" 1812 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1813 | dependencies = [ 1814 | "try-lock", 1815 | ] 1816 | 1817 | [[package]] 1818 | name = "wasi" 1819 | version = "0.11.0+wasi-snapshot-preview1" 1820 | source = "registry+https://github.com/rust-lang/crates.io-index" 1821 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1822 | 1823 | [[package]] 1824 | name = "wasm-bindgen" 1825 | version = "0.2.100" 1826 | source = "registry+https://github.com/rust-lang/crates.io-index" 1827 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 1828 | dependencies = [ 1829 | "cfg-if", 1830 | "once_cell", 1831 | "rustversion", 1832 | "wasm-bindgen-macro", 1833 | ] 1834 | 1835 | [[package]] 1836 | name = "wasm-bindgen-backend" 1837 | version = "0.2.100" 1838 | source = "registry+https://github.com/rust-lang/crates.io-index" 1839 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 1840 | dependencies = [ 1841 | "bumpalo", 1842 | "log", 1843 | "proc-macro2", 1844 | "quote", 1845 | "syn", 1846 | "wasm-bindgen-shared", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "wasm-bindgen-futures" 1851 | version = "0.4.50" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" 1854 | dependencies = [ 1855 | "cfg-if", 1856 | "js-sys", 1857 | "once_cell", 1858 | "wasm-bindgen", 1859 | "web-sys", 1860 | ] 1861 | 1862 | [[package]] 1863 | name = "wasm-bindgen-macro" 1864 | version = "0.2.100" 1865 | source = "registry+https://github.com/rust-lang/crates.io-index" 1866 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 1867 | dependencies = [ 1868 | "quote", 1869 | "wasm-bindgen-macro-support", 1870 | ] 1871 | 1872 | [[package]] 1873 | name = "wasm-bindgen-macro-support" 1874 | version = "0.2.100" 1875 | source = "registry+https://github.com/rust-lang/crates.io-index" 1876 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 1877 | dependencies = [ 1878 | "proc-macro2", 1879 | "quote", 1880 | "syn", 1881 | "wasm-bindgen-backend", 1882 | "wasm-bindgen-shared", 1883 | ] 1884 | 1885 | [[package]] 1886 | name = "wasm-bindgen-shared" 1887 | version = "0.2.100" 1888 | source = "registry+https://github.com/rust-lang/crates.io-index" 1889 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 1890 | dependencies = [ 1891 | "unicode-ident", 1892 | ] 1893 | 1894 | [[package]] 1895 | name = "web-sys" 1896 | version = "0.3.77" 1897 | source = "registry+https://github.com/rust-lang/crates.io-index" 1898 | checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" 1899 | dependencies = [ 1900 | "js-sys", 1901 | "wasm-bindgen", 1902 | ] 1903 | 1904 | [[package]] 1905 | name = "winapi" 1906 | version = "0.3.9" 1907 | source = "registry+https://github.com/rust-lang/crates.io-index" 1908 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1909 | dependencies = [ 1910 | "winapi-i686-pc-windows-gnu", 1911 | "winapi-x86_64-pc-windows-gnu", 1912 | ] 1913 | 1914 | [[package]] 1915 | name = "winapi-i686-pc-windows-gnu" 1916 | version = "0.4.0" 1917 | source = "registry+https://github.com/rust-lang/crates.io-index" 1918 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1919 | 1920 | [[package]] 1921 | name = "winapi-util" 1922 | version = "0.1.9" 1923 | source = "registry+https://github.com/rust-lang/crates.io-index" 1924 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1925 | dependencies = [ 1926 | "windows-sys 0.59.0", 1927 | ] 1928 | 1929 | [[package]] 1930 | name = "winapi-x86_64-pc-windows-gnu" 1931 | version = "0.4.0" 1932 | source = "registry+https://github.com/rust-lang/crates.io-index" 1933 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1934 | 1935 | [[package]] 1936 | name = "windows-registry" 1937 | version = "0.2.0" 1938 | source = "registry+https://github.com/rust-lang/crates.io-index" 1939 | checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" 1940 | dependencies = [ 1941 | "windows-result", 1942 | "windows-strings", 1943 | "windows-targets 0.52.6", 1944 | ] 1945 | 1946 | [[package]] 1947 | name = "windows-result" 1948 | version = "0.2.0" 1949 | source = "registry+https://github.com/rust-lang/crates.io-index" 1950 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 1951 | dependencies = [ 1952 | "windows-targets 0.52.6", 1953 | ] 1954 | 1955 | [[package]] 1956 | name = "windows-strings" 1957 | version = "0.1.0" 1958 | source = "registry+https://github.com/rust-lang/crates.io-index" 1959 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 1960 | dependencies = [ 1961 | "windows-result", 1962 | "windows-targets 0.52.6", 1963 | ] 1964 | 1965 | [[package]] 1966 | name = "windows-sys" 1967 | version = "0.45.0" 1968 | source = "registry+https://github.com/rust-lang/crates.io-index" 1969 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 1970 | dependencies = [ 1971 | "windows-targets 0.42.2", 1972 | ] 1973 | 1974 | [[package]] 1975 | name = "windows-sys" 1976 | version = "0.52.0" 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" 1978 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1979 | dependencies = [ 1980 | "windows-targets 0.52.6", 1981 | ] 1982 | 1983 | [[package]] 1984 | name = "windows-sys" 1985 | version = "0.59.0" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1988 | dependencies = [ 1989 | "windows-targets 0.52.6", 1990 | ] 1991 | 1992 | [[package]] 1993 | name = "windows-targets" 1994 | version = "0.42.2" 1995 | source = "registry+https://github.com/rust-lang/crates.io-index" 1996 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" 1997 | dependencies = [ 1998 | "windows_aarch64_gnullvm 0.42.2", 1999 | "windows_aarch64_msvc 0.42.2", 2000 | "windows_i686_gnu 0.42.2", 2001 | "windows_i686_msvc 0.42.2", 2002 | "windows_x86_64_gnu 0.42.2", 2003 | "windows_x86_64_gnullvm 0.42.2", 2004 | "windows_x86_64_msvc 0.42.2", 2005 | ] 2006 | 2007 | [[package]] 2008 | name = "windows-targets" 2009 | version = "0.52.6" 2010 | source = "registry+https://github.com/rust-lang/crates.io-index" 2011 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2012 | dependencies = [ 2013 | "windows_aarch64_gnullvm 0.52.6", 2014 | "windows_aarch64_msvc 0.52.6", 2015 | "windows_i686_gnu 0.52.6", 2016 | "windows_i686_gnullvm", 2017 | "windows_i686_msvc 0.52.6", 2018 | "windows_x86_64_gnu 0.52.6", 2019 | "windows_x86_64_gnullvm 0.52.6", 2020 | "windows_x86_64_msvc 0.52.6", 2021 | ] 2022 | 2023 | [[package]] 2024 | name = "windows_aarch64_gnullvm" 2025 | version = "0.42.2" 2026 | source = "registry+https://github.com/rust-lang/crates.io-index" 2027 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" 2028 | 2029 | [[package]] 2030 | name = "windows_aarch64_gnullvm" 2031 | version = "0.52.6" 2032 | source = "registry+https://github.com/rust-lang/crates.io-index" 2033 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2034 | 2035 | [[package]] 2036 | name = "windows_aarch64_msvc" 2037 | version = "0.42.2" 2038 | source = "registry+https://github.com/rust-lang/crates.io-index" 2039 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" 2040 | 2041 | [[package]] 2042 | name = "windows_aarch64_msvc" 2043 | version = "0.52.6" 2044 | source = "registry+https://github.com/rust-lang/crates.io-index" 2045 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2046 | 2047 | [[package]] 2048 | name = "windows_i686_gnu" 2049 | version = "0.42.2" 2050 | source = "registry+https://github.com/rust-lang/crates.io-index" 2051 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" 2052 | 2053 | [[package]] 2054 | name = "windows_i686_gnu" 2055 | version = "0.52.6" 2056 | source = "registry+https://github.com/rust-lang/crates.io-index" 2057 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2058 | 2059 | [[package]] 2060 | name = "windows_i686_gnullvm" 2061 | version = "0.52.6" 2062 | source = "registry+https://github.com/rust-lang/crates.io-index" 2063 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2064 | 2065 | [[package]] 2066 | name = "windows_i686_msvc" 2067 | version = "0.42.2" 2068 | source = "registry+https://github.com/rust-lang/crates.io-index" 2069 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" 2070 | 2071 | [[package]] 2072 | name = "windows_i686_msvc" 2073 | version = "0.52.6" 2074 | source = "registry+https://github.com/rust-lang/crates.io-index" 2075 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2076 | 2077 | [[package]] 2078 | name = "windows_x86_64_gnu" 2079 | version = "0.42.2" 2080 | source = "registry+https://github.com/rust-lang/crates.io-index" 2081 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" 2082 | 2083 | [[package]] 2084 | name = "windows_x86_64_gnu" 2085 | version = "0.52.6" 2086 | source = "registry+https://github.com/rust-lang/crates.io-index" 2087 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2088 | 2089 | [[package]] 2090 | name = "windows_x86_64_gnullvm" 2091 | version = "0.42.2" 2092 | source = "registry+https://github.com/rust-lang/crates.io-index" 2093 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" 2094 | 2095 | [[package]] 2096 | name = "windows_x86_64_gnullvm" 2097 | version = "0.52.6" 2098 | source = "registry+https://github.com/rust-lang/crates.io-index" 2099 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2100 | 2101 | [[package]] 2102 | name = "windows_x86_64_msvc" 2103 | version = "0.42.2" 2104 | source = "registry+https://github.com/rust-lang/crates.io-index" 2105 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" 2106 | 2107 | [[package]] 2108 | name = "windows_x86_64_msvc" 2109 | version = "0.52.6" 2110 | source = "registry+https://github.com/rust-lang/crates.io-index" 2111 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2112 | 2113 | [[package]] 2114 | name = "write16" 2115 | version = "1.0.0" 2116 | source = "registry+https://github.com/rust-lang/crates.io-index" 2117 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 2118 | 2119 | [[package]] 2120 | name = "writeable" 2121 | version = "0.5.5" 2122 | source = "registry+https://github.com/rust-lang/crates.io-index" 2123 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 2124 | 2125 | [[package]] 2126 | name = "xattr" 2127 | version = "1.4.0" 2128 | source = "registry+https://github.com/rust-lang/crates.io-index" 2129 | checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" 2130 | dependencies = [ 2131 | "libc", 2132 | "linux-raw-sys", 2133 | "rustix", 2134 | ] 2135 | 2136 | [[package]] 2137 | name = "yoke" 2138 | version = "0.7.5" 2139 | source = "registry+https://github.com/rust-lang/crates.io-index" 2140 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 2141 | dependencies = [ 2142 | "serde", 2143 | "stable_deref_trait", 2144 | "yoke-derive", 2145 | "zerofrom", 2146 | ] 2147 | 2148 | [[package]] 2149 | name = "yoke-derive" 2150 | version = "0.7.5" 2151 | source = "registry+https://github.com/rust-lang/crates.io-index" 2152 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 2153 | dependencies = [ 2154 | "proc-macro2", 2155 | "quote", 2156 | "syn", 2157 | "synstructure", 2158 | ] 2159 | 2160 | [[package]] 2161 | name = "zerocopy" 2162 | version = "0.7.35" 2163 | source = "registry+https://github.com/rust-lang/crates.io-index" 2164 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2165 | dependencies = [ 2166 | "byteorder", 2167 | "zerocopy-derive", 2168 | ] 2169 | 2170 | [[package]] 2171 | name = "zerocopy-derive" 2172 | version = "0.7.35" 2173 | source = "registry+https://github.com/rust-lang/crates.io-index" 2174 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2175 | dependencies = [ 2176 | "proc-macro2", 2177 | "quote", 2178 | "syn", 2179 | ] 2180 | 2181 | [[package]] 2182 | name = "zerofrom" 2183 | version = "0.1.5" 2184 | source = "registry+https://github.com/rust-lang/crates.io-index" 2185 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 2186 | dependencies = [ 2187 | "zerofrom-derive", 2188 | ] 2189 | 2190 | [[package]] 2191 | name = "zerofrom-derive" 2192 | version = "0.1.5" 2193 | source = "registry+https://github.com/rust-lang/crates.io-index" 2194 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 2195 | dependencies = [ 2196 | "proc-macro2", 2197 | "quote", 2198 | "syn", 2199 | "synstructure", 2200 | ] 2201 | 2202 | [[package]] 2203 | name = "zeroize" 2204 | version = "1.8.1" 2205 | source = "registry+https://github.com/rust-lang/crates.io-index" 2206 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2207 | dependencies = [ 2208 | "zeroize_derive", 2209 | ] 2210 | 2211 | [[package]] 2212 | name = "zeroize_derive" 2213 | version = "1.4.2" 2214 | source = "registry+https://github.com/rust-lang/crates.io-index" 2215 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 2216 | dependencies = [ 2217 | "proc-macro2", 2218 | "quote", 2219 | "syn", 2220 | ] 2221 | 2222 | [[package]] 2223 | name = "zerovec" 2224 | version = "0.10.4" 2225 | source = "registry+https://github.com/rust-lang/crates.io-index" 2226 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 2227 | dependencies = [ 2228 | "yoke", 2229 | "zerofrom", 2230 | "zerovec-derive", 2231 | ] 2232 | 2233 | [[package]] 2234 | name = "zerovec-derive" 2235 | version = "0.10.3" 2236 | source = "registry+https://github.com/rust-lang/crates.io-index" 2237 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 2238 | dependencies = [ 2239 | "proc-macro2", 2240 | "quote", 2241 | "syn", 2242 | ] 2243 | 2244 | [[package]] 2245 | name = "zip" 2246 | version = "2.2.2" 2247 | source = "registry+https://github.com/rust-lang/crates.io-index" 2248 | checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45" 2249 | dependencies = [ 2250 | "aes", 2251 | "arbitrary", 2252 | "bzip2", 2253 | "constant_time_eq", 2254 | "crc32fast", 2255 | "crossbeam-utils", 2256 | "deflate64", 2257 | "displaydoc", 2258 | "flate2", 2259 | "hmac", 2260 | "indexmap", 2261 | "lzma-rs", 2262 | "memchr", 2263 | "pbkdf2", 2264 | "rand", 2265 | "sha1", 2266 | "thiserror 2.0.11", 2267 | "time", 2268 | "zeroize", 2269 | "zopfli", 2270 | "zstd", 2271 | ] 2272 | 2273 | [[package]] 2274 | name = "zopfli" 2275 | version = "0.8.1" 2276 | source = "registry+https://github.com/rust-lang/crates.io-index" 2277 | checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" 2278 | dependencies = [ 2279 | "bumpalo", 2280 | "crc32fast", 2281 | "lockfree-object-pool", 2282 | "log", 2283 | "once_cell", 2284 | "simd-adler32", 2285 | ] 2286 | 2287 | [[package]] 2288 | name = "zstd" 2289 | version = "0.13.2" 2290 | source = "registry+https://github.com/rust-lang/crates.io-index" 2291 | checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" 2292 | dependencies = [ 2293 | "zstd-safe", 2294 | ] 2295 | 2296 | [[package]] 2297 | name = "zstd-safe" 2298 | version = "7.2.1" 2299 | source = "registry+https://github.com/rust-lang/crates.io-index" 2300 | checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" 2301 | dependencies = [ 2302 | "zstd-sys", 2303 | ] 2304 | 2305 | [[package]] 2306 | name = "zstd-sys" 2307 | version = "2.0.13+zstd.1.5.6" 2308 | source = "registry+https://github.com/rust-lang/crates.io-index" 2309 | checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" 2310 | dependencies = [ 2311 | "cc", 2312 | "pkg-config", 2313 | ] 2314 | -------------------------------------------------------------------------------- /native/rustreader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustreader" 3 | version = "0.1.0" 4 | authors = [] 5 | edition = "2021" 6 | 7 | [lib] 8 | name = "rustreader" 9 | path = "src/lib.rs" 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | rustler = "0.36.0" 14 | extractous = "0.2.0" 15 | -------------------------------------------------------------------------------- /native/rustreader/README.md: -------------------------------------------------------------------------------- 1 | # NIF for Elixir.RustReader 2 | 3 | ## To build the NIF module: 4 | 5 | - Your NIF will now build along with your project. 6 | 7 | ## To load the NIF: 8 | 9 | ```elixir 10 | defmodule RustReader do 11 | use Rustler, otp_app: :elixir_pdf, crate: "rustreader" 12 | 13 | # When your NIF is loaded, it will override this function. 14 | def add(_a, _b), do: :erlang.nif_error(:nif_not_loaded) 15 | end 16 | ``` 17 | 18 | ## Examples 19 | 20 | [This](https://github.com/rusterlium/NifIo) is a complete example of a NIF written in Rust. 21 | -------------------------------------------------------------------------------- /native/rustreader/src/lib.rs: -------------------------------------------------------------------------------- 1 | use extractous::Extractor; 2 | use rustler::{Encoder, Env, NifResult, Term}; 3 | 4 | #[rustler::nif] 5 | fn extract_pdf(path: String) -> NifResult<(String, String)> { 6 | let extractor = Extractor::new(); 7 | 8 | match extractor.extract_file_to_string(&path) { 9 | Ok((content, metadata)) => Ok((content, format!("{:?}", metadata))), 10 | Err(e) => Err(rustler::Error::Term(Box::new(format!("Extraction failed: {}", e)))) 11 | } 12 | } 13 | 14 | rustler::init!("Elixir.RustReader", [extract_pdf]); 15 | -------------------------------------------------------------------------------- /priv/gettext/en/LC_MESSAGES/errors.po: -------------------------------------------------------------------------------- 1 | ## `msgid`s in this file come from POT (.pot) files. 2 | ## 3 | ## Do not add, change, or remove `msgid`s manually here as 4 | ## they're tied to the ones in the corresponding POT file 5 | ## (with the same domain). 6 | ## 7 | ## Use `mix gettext.extract --merge` or `mix gettext.merge` 8 | ## to merge POT files into PO files. 9 | msgid "" 10 | msgstr "" 11 | "Language: en\n" 12 | -------------------------------------------------------------------------------- /priv/gettext/errors.pot: -------------------------------------------------------------------------------- 1 | ## This is a PO Template file. 2 | ## 3 | ## `msgid`s here are often extracted from source code. 4 | ## Add new translations manually only if they're dynamic 5 | ## translations that can't be statically extracted. 6 | ## 7 | ## Run `mix gettext.extract` to bring this file up to 8 | ## date. Leave `msgstr`s empty as changing them here has no 9 | ## effect: edit them in PO (`.po`) files instead. 10 | 11 | -------------------------------------------------------------------------------- /priv/native/librustreader.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgreg/elixir_pdf_tutorial/e5b3f298bb474840c4d4599a018fd6405bb39014/priv/native/librustreader.so -------------------------------------------------------------------------------- /priv/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgreg/elixir_pdf_tutorial/e5b3f298bb474840c4d4599a018fd6405bb39014/priv/static/favicon.ico -------------------------------------------------------------------------------- /priv/static/images/logo.svg: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /priv/static/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /test/elixir_pdf_web/controllers/error_html_test.exs: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.ErrorHTMLTest do 2 | use ElixirPdfWeb.ConnCase, async: true 3 | 4 | # Bring render_to_string/4 for testing custom views 5 | import Phoenix.Template 6 | 7 | test "renders 404.html" do 8 | assert render_to_string(ElixirPdfWeb.ErrorHTML, "404", "html", []) == "Not Found" 9 | end 10 | 11 | test "renders 500.html" do 12 | assert render_to_string(ElixirPdfWeb.ErrorHTML, "500", "html", []) == "Internal Server Error" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/elixir_pdf_web/controllers/error_json_test.exs: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.ErrorJSONTest do 2 | use ElixirPdfWeb.ConnCase, async: true 3 | 4 | test "renders 404" do 5 | assert ElixirPdfWeb.ErrorJSON.render("404.json", %{}) == %{errors: %{detail: "Not Found"}} 6 | end 7 | 8 | test "renders 500" do 9 | assert ElixirPdfWeb.ErrorJSON.render("500.json", %{}) == 10 | %{errors: %{detail: "Internal Server Error"}} 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /test/elixir_pdf_web/controllers/page_controller_test.exs: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.PageControllerTest do 2 | use ElixirPdfWeb.ConnCase 3 | 4 | test "GET /", %{conn: conn} do 5 | conn = get(conn, ~p"/") 6 | assert html_response(conn, 200) =~ "Peace of mind from prototype to production" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/support/conn_case.ex: -------------------------------------------------------------------------------- 1 | defmodule ElixirPdfWeb.ConnCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | tests that require setting up a connection. 5 | 6 | Such tests rely on `Phoenix.ConnTest` and also 7 | import other functionality to make it easier 8 | to build common data structures and query the data layer. 9 | 10 | Finally, if the test case interacts with the database, 11 | we enable the SQL sandbox, so changes done to the database 12 | are reverted at the end of every test. If you are using 13 | PostgreSQL, you can even run database tests asynchronously 14 | by setting `use ElixirPdfWeb.ConnCase, async: true`, although 15 | this option is not recommended for other databases. 16 | """ 17 | 18 | use ExUnit.CaseTemplate 19 | 20 | using do 21 | quote do 22 | # The default endpoint for testing 23 | @endpoint ElixirPdfWeb.Endpoint 24 | 25 | use ElixirPdfWeb, :verified_routes 26 | 27 | # Import conveniences for testing with connections 28 | import Plug.Conn 29 | import Phoenix.ConnTest 30 | import ElixirPdfWeb.ConnCase 31 | end 32 | end 33 | 34 | setup _tags do 35 | {:ok, conn: Phoenix.ConnTest.build_conn()} 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | --------------------------------------------------------------------------------