Skip to content

Commit

Permalink
new graphql url config option
Browse files Browse the repository at this point in the history
  • Loading branch information
mrnaveira committed Feb 21, 2025
1 parent 249a0f3 commit 9d4730d
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 22 deletions.
11 changes: 10 additions & 1 deletion applications/tari_indexer/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,12 @@ pub struct Cli {
pub reachability: Option<ReachabilityMode>,
#[clap(long)]
pub disable_mdns: bool,
/// Public address of the Web UI
/// Public address of the JSON RPC
#[clap(long, env = "TARI_INDEXER_WEB_UI_PUBLIC_JSON_RPC_URL")]
pub web_ui_public_json_rpc_url: Option<String>,
/// Public address of the GraphQL API
#[clap(long, env = "TARI_INDEXER_WEB_UI_PUBLIC_GRAPHQL_URL")]
pub web_ui_public_graphql_url: Option<String>,
}

impl Cli {
Expand Down Expand Up @@ -96,6 +99,12 @@ impl ConfigOverrideProvider for Cli {
json_rpc_url.to_string(),
));
}
if let Some(ref graphql_url) = self.web_ui_public_graphql_url {
overrides.push((
"indexer.web_ui_public_graphql_url".to_string(),
graphql_url.to_string(),
));
}
if let Some(reachability) = self.reachability {
overrides.push(("indexer.p2p.reachability_mode".to_string(), reachability.to_string()));
}
Expand Down
6 changes: 5 additions & 1 deletion applications/tari_indexer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,12 @@ pub struct IndexerConfig {
pub graphql_address: Option<SocketAddr>,
/// The address of the HTTP UI
pub web_ui_address: Option<SocketAddr>,
/// The jrpc address where the UI should connect (it can be the same as the json_rpc_address, but doesn't have to
/// The jrpc address where the UI should connect to the JSON RPC (it can be the same as the json_rpc_address, but doesn't have to
/// be), if this will be None, then the listen_addr will be used.
pub web_ui_public_json_rpc_url: Option<String>,
/// The jrpc address where the UI should connect to the GraphQL API(it can be the same as the json_rpc_address, but doesn't have to
/// be), if this will be None, then the listen_addr will be used.
pub web_ui_public_graphql_url: Option<String>,
/// How often do we want to scan the second layer for new versions
#[serde(with = "serializers::seconds")]
pub dan_layer_scanning_internal: Duration,
Expand Down Expand Up @@ -131,6 +134,7 @@ impl Default for IndexerConfig {
graphql_address: Some("127.0.0.1:18301".parse().unwrap()),
web_ui_address: Some("127.0.0.1:15000".parse().unwrap()),
web_ui_public_json_rpc_url: None,
web_ui_public_graphql_url: None,
dan_layer_scanning_internal: Duration::from_secs(10),
templates: TemplateConfig::default(),
sidechain_id: None,
Expand Down
4 changes: 3 additions & 1 deletion applications/tari_indexer/src/http_ui/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ use url::Url;

const LOG_TARGET: &str = "tari::indexer::web_ui::server";

pub async fn run_http_ui_server(address: SocketAddr, json_rpc_address: Url) -> Result<(), anyhow::Error> {
pub async fn run_http_ui_server(address: SocketAddr, json_rpc_address: Url, graphql_address: Url) -> Result<(), anyhow::Error> {
let json_rpc_address = Arc::new(json_rpc_address);

let router = Router::new()
.route("/json_rpc_address", get(|| async move { json_rpc_address.to_string() }))
.route("/graphql_address", get(|| async move { graphql_address.to_string() }))
.fallback(handler);

info!(target: LOG_TARGET, "🕸️ HTTP UI started at {}", address);
Expand Down
46 changes: 30 additions & 16 deletions applications/tari_indexer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,22 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow
services.template_manager.clone(),
);

// Run the event manager
let event_manager = Arc::new(EventManager::new(
services.substate_store.clone(),
dan_layer_scanner.clone(),
));

// Run the GraphQL API
let graphql_address = config.indexer.graphql_address;
if let Some(address) = graphql_address {
info!(target: LOG_TARGET, "🌐 Started GraphQL server on {}", address);
task::spawn(run_graphql(address, substate_manager.clone(), event_manager.clone()));
}

// Run the JSON-RPC API
let jrpc_address = config.indexer.json_rpc_address;
if let Some(jrpc_address) = jrpc_address {
if let (Some(jrpc_address), Some(graphql_address)) = (jrpc_address, graphql_address) {
info!(target: LOG_TARGET, "🌐 Started JSON-RPC server on {}", jrpc_address);
let handlers = JsonRpcHandlers::new(
&services,
Expand All @@ -152,26 +165,32 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow
let jrpc_address = spawn_json_rpc(jrpc_address, handlers)?;
// Run the http ui
if let Some(address) = config.indexer.web_ui_address {
// json rpc
let mut public_jrpc_address = config
.indexer
.web_ui_public_json_rpc_url
.unwrap_or_else(|| jrpc_address.to_string());
if !public_jrpc_address.starts_with("http://") && !public_jrpc_address.starts_with("https://") {
public_jrpc_address = format!("http://{}", public_jrpc_address);
}

let public_jrpc_address = url::Url::parse(&public_jrpc_address)
.map_err(|err| ExitError::new(ExitCode::ConfigError, format!("Invalid public JSON-rpc url: {err}")))?;
task::spawn(run_http_ui_server(address, public_jrpc_address));
}
}

// Run the event manager
let event_manager = Arc::new(EventManager::new(
services.substate_store.clone(),
dan_layer_scanner.clone(),
));
// graphql
let mut public_graphql_address = config
.indexer
.web_ui_public_graphql_url
.unwrap_or_else(|| graphql_address.to_string());
if !public_graphql_address.starts_with("http://") && !public_graphql_address.starts_with("https://") {
public_graphql_address = format!("http://{}", public_graphql_address);
}
let public_graphql_address = url::Url::parse(&public_graphql_address)
.map_err(|err| ExitError::new(ExitCode::ConfigError, format!("Invalid public GraphQL url: {err}")))?;

task::spawn(run_http_ui_server(address, public_jrpc_address, public_graphql_address));
}
}

// Run the event scanner
let event_filters: Vec<EventFilter> = config
.indexer
Expand All @@ -188,12 +207,7 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow
event_filters,
);

// Run the GraphQL API
let graphql_address = config.indexer.graphql_address;
if let Some(address) = graphql_address {
info!(target: LOG_TARGET, "🌐 Started GraphQL server on {}", address);
task::spawn(run_graphql(address, substate_manager.clone(), event_manager.clone()));
}


// Create pid to allow watchers to know that the process has started
fs::write(config.common.base_path.join("pid"), std::process::id().to_string())
Expand Down
7 changes: 5 additions & 2 deletions applications/tari_indexer_web_ui/src/routes/Events/Events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import KeyboardArrowLeftIcon from '@mui/icons-material/KeyboardArrowLeft';
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
import saveAs from "file-saver";
import JsonDialog from "../../Components/JsonDialog";
import { getGraphQLAddress } from "../../utils/graphql";

const INDEXER_ADDRESS = "http://localhost:18301";
const PAGE_SIZE = 10;

function EventsLayout() {
Expand All @@ -59,7 +59,10 @@ function EventsLayout() {
graphql_filters += `substateId:"${filter.substate_id}", `;
}

let res = await fetch(INDEXER_ADDRESS, {
let indexer_address = (await getGraphQLAddress()).toString();
console.log({indexer_address});

let res = await fetch(indexer_address, {
method: 'POST',

headers: {
Expand Down
45 changes: 45 additions & 0 deletions applications/tari_indexer_web_ui/src/utils/graphql.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2025. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

const DEFAULT_GRAPHQL_ADDRESS = new URL(
import.meta.env.VITE_INDEXER_GRAPHQL_ADDRESS ||
import.meta.env.VITE_GRAPHQL_ADDRESS ||
"http://localhost:18301",
);

export async function getGraphQLAddress(): Promise<URL> {
try {
const resp = await fetch("/graphql_address");
if (resp.status === 200) {
const url = await resp.text();
try {
return new URL(url);
} catch (e) {
throw new Error(`Invalid URL: ${url} : {e}`);
}
}
} catch (e) {
console.warn(e);
}

return DEFAULT_GRAPHQL_ADDRESS;
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,25 @@ impl<'a> ProcessContext<'a> {
.port_allocator
.get("jrpc")
.expect("JSON-rpc port must be allocated before calling get_public_json_rpc_url");
format!("http://{public_ip}:{port}").parse().expect("Invalid web URL")
format!("http://{public_ip}:{port}").parse().expect("Invalid JSON RPC URL")
},
}
}

pub fn get_public_graphql_url(&self) -> Url {
match self.settings.get("public_graphql_url") {
Some(url) => url.parse().expect("Invalid GraphQL URL"),
None => {
let public_ip = self
.settings
.get("public_ip")
.map(|s| s.as_str())
.unwrap_or("127.0.0.1");
let port = self
.port_allocator
.get("graphql")
.expect("Graphql port must be allocated before calling get_graphql_url");
format!("http://{public_ip}:{port}").parse().expect("Invalid GraphQL URL")
},
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ impl ProcessDefinition for Indexer {
async fn get_command(&self, mut context: ProcessContext<'_>) -> anyhow::Result<Command> {
let mut command = Command::new(context.bin());
let jrpc_port = context.get_free_port("jrpc").await?;
let graphql_port = context.get_free_port("graphql").await?;
let web_ui_port = context.get_free_port("web").await?;
let listen_ip = context.listen_ip();

let json_rpc_public_url = context.get_public_json_rpc_url();
let graphql_public_url = context.get_public_graphql_url();
let json_rpc_listener_address = format!("{listen_ip}:{jrpc_port}");
let graphql_listener_address = format!("{listen_ip}:{graphql_port}");
let web_ui_listener_address = format!("{listen_ip}:{web_ui_port}");

let base_node = context
Expand All @@ -52,8 +55,10 @@ impl ProcessDefinition for Indexer {
"-pepoch_oracle.base_layer.base_node_grpc_url={base_node_grpc_url}"
))
.arg(format!("-pindexer.json_rpc_address={json_rpc_listener_address}"))
.arg(format!("-pindexer.graphql_address={graphql_listener_address}"))
.arg(format!("-pindexer.web_ui_address={web_ui_listener_address}"))
.arg(format!("-pindexer.web_ui_public_json_rpc_url={json_rpc_public_url}"))
.arg(format!("-pindexer.web_ui_public_graphql_url={graphql_public_url}"))
.arg("-pepoch_oracle.base_layer.scanning_interval=1");

Ok(command)
Expand Down
17 changes: 17 additions & 0 deletions applications/tari_swarm_daemon/src/process_manager/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,23 @@ impl InstanceInfo {
},
}
}

pub fn get_public_graphql_url(&self) -> Url {
match self.settings.get("public_graphql_url") {
Some(url) => url.parse().expect("Invalid JSON RPC URL"),
None => {
let public_ip = self
.settings
.get("public_ip")
.map(|s| s.as_str())
.unwrap_or("127.0.0.1");
let web_port = self.ports.get("jrpc").expect("jrpc port not found");
format!("http://{public_ip}:{web_port}/json_rpc")
.parse()
.expect("Invalid web URL")
},
}
}
}

impl From<&Instance> for InstanceInfo {
Expand Down
3 changes: 3 additions & 0 deletions applications/tari_swarm_daemon/src/webserver/rpc/indexers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct IndexerInfo {
pub name: String,
pub web: Url,
pub jrpc: Url,
pub graphql: Url,
pub is_running: bool,
}

Expand All @@ -32,13 +33,15 @@ pub async fn list(context: &HandlerContext, _req: ListIndexersRequest) -> Result
.into_iter()
.map(|instance| {
let jrpc = instance.get_public_json_rpc_url();
let graphql: Url = instance.get_public_graphql_url();
let web = instance.get_public_web_url();

Ok(IndexerInfo {
instance_id: instance.id,
name: instance.name,
web,
jrpc,
graphql,
is_running: instance.is_running,
})
})
Expand Down

0 comments on commit 9d4730d

Please sign in to comment.