parent
f15ca8eeee
commit
9bcdea8204
@ -0,0 +1,41 @@ |
||||
defmodule BlockScoutWeb.VisualizeSol2umlController do |
||||
use BlockScoutWeb, :controller |
||||
alias Explorer.Chain |
||||
alias Explorer.Visualize.Sol2uml |
||||
|
||||
def index(conn, %{"address" => address_hash_string}) do |
||||
address_options = [ |
||||
necessity_by_association: %{ |
||||
:contracts_creation_internal_transaction => :optional, |
||||
:names => :optional, |
||||
:smart_contract => :optional, |
||||
:token => :optional, |
||||
:contracts_creation_transaction => :optional |
||||
} |
||||
] |
||||
with true <- Sol2uml.enabled?(), |
||||
true <- Chain.smart_contract_fully_verified?(address_hash_string), |
||||
{:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), |
||||
{:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do |
||||
sources = address.smart_contract_additional_sources |
||||
|> Enum.map(fn (additional_source) -> {additional_source.file_name, additional_source.contract_source_code} end) |
||||
|> Enum.into(%{}) |
||||
|> Map.merge(%{ |
||||
address.smart_contract.file_path => address.smart_contract.contract_source_code |
||||
}) |
||||
params = %{ |
||||
sources: sources |
||||
} |
||||
case Sol2uml.visualize_contracts(params) do |
||||
{:ok, svg} -> render(conn, "index.html", address: address, svg: svg, error: nil) |
||||
{:error, error} -> render(conn, "index.html", address: address, svg: nil, error: error) |
||||
end |
||||
else |
||||
_ -> not_found(conn) |
||||
end |
||||
end |
||||
|
||||
def index(conn, params) do |
||||
not_found(conn) |
||||
end |
||||
end |
@ -0,0 +1,16 @@ |
||||
<section class="container"> |
||||
<div class="card"> |
||||
<div class="card-body fs-14"> |
||||
<div class="card-title lg-card-title mb-2"> |
||||
<h1><%= gettext("UML diagram") %></h1> |
||||
<%= gettext("For contract") %> <%= link( |
||||
@address.hash, |
||||
to: address_contract_path(@conn, :index, @address.hash) |
||||
) %> |
||||
</div> |
||||
<div class="row d-flex justify-content-center"> |
||||
<img src="data:image/svg+xml;base64,<%= @svg %>"/> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</section> |
@ -0,0 +1,3 @@ |
||||
defmodule BlockScoutWeb.VisualizeSol2umlView do |
||||
use BlockScoutWeb, :view |
||||
end |
@ -0,0 +1,74 @@ |
||||
defmodule Explorer.Visualize.Sol2uml do |
||||
@moduledoc """ |
||||
Adapter for sol2uml visualizer with https://github.com/blockscout/blockscout-rs/blob/main/visualizer |
||||
""" |
||||
alias HTTPoison.Response |
||||
require Logger |
||||
|
||||
@post_timeout :infinity |
||||
@request_error_msg "Error while sending request to visualizer microservice" |
||||
|
||||
def visualize_contracts(body) do |
||||
http_post_request(visualize_contracts_url(), body) |
||||
end |
||||
|
||||
def http_post_request(url, body) do |
||||
headers = [{"Content-Type", "application/json"}] |
||||
|
||||
case HTTPoison.post(url, Jason.encode!(body), headers, recv_timeout: @post_timeout) do |
||||
{:ok, %Response{body: body, status_code: 200}} -> |
||||
proccess_visualizer_response(body) |
||||
|
||||
{:ok, %Response{body: body, status_code: _}} -> |
||||
proccess_visualizer_response(body) |
||||
|
||||
{:error, error} -> |
||||
old_truncate = Application.get_env(:logger, :truncate) |
||||
Logger.configure(truncate: :infinity) |
||||
|
||||
Logger.error(fn -> |
||||
[ |
||||
"Error while sending request to visualizer microservice. url: #{url}, body: #{inspect(body, limit: :infinity, printable_limit: :infinity)}: ", |
||||
inspect(error, limit: :infinity, printable_limit: :infinity) |
||||
] |
||||
end) |
||||
|
||||
Logger.configure(truncate: old_truncate) |
||||
{:error, @request_error_msg} |
||||
end |
||||
end |
||||
|
||||
|
||||
def proccess_visualizer_response(body) when is_binary(body) do |
||||
case Jason.decode(body) do |
||||
{:ok, decoded} -> |
||||
proccess_visualizer_response(decoded) |
||||
|
||||
_ -> |
||||
{:error, body} |
||||
end |
||||
end |
||||
|
||||
def proccess_visualizer_response(%{"svg" => svg}) do |
||||
{:ok, svg} |
||||
end |
||||
|
||||
def proccess_visualizer_response(other), do: {:error, other} |
||||
|
||||
def visualize_contracts_url, do: "#{base_api_url()}" <> "/solidity:visualizeContracts" |
||||
|
||||
def base_api_url, do: "#{base_url()}" <> "/api/v1" |
||||
|
||||
def base_url do |
||||
url = Application.get_env(:explorer, __MODULE__)[:service_url] |
||||
|
||||
if String.ends_with?(url, "/") do |
||||
url |
||||
|> String.slice(0..(String.length(url) - 2)) |
||||
else |
||||
url |
||||
end |
||||
end |
||||
|
||||
def enabled?, do: Application.get_env(:explorer, __MODULE__)[:enabled] |
||||
end |
Loading…
Reference in new issue