Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add libpq to docker image, add script and readme #5

Merged
merged 4 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ POSTGRES_USER="postgres"
POSTGRES_PASSWORD="localpw"
POSTGRES_URI="localhost"
POSTGRES_PORT="5432"
POSTGRES_DB_NAME="forc_pub"
DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_URI}/${POSTGRES_DB_NAME}"
POSTGRES_DB_NAME="forc_pub"
109 changes: 108 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,111 @@
[![docs](https://docs.rs/forc/badge.svg)](https://docs.rs/forc/)
[![discord](https://img.shields.io/badge/chat%20on-discord-orange?&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/xfpK4Pe)

Welcome to the GitHub repository for [forc.pub](https://forc.pub/), the official package registry for the Sway programming language.
Welcome to the GitHub repository for [forc.pub](https://forc.pub/), the official package registry for the Sway programming language.

## How it Works

`forc.pub` has a simple multi-threaded Rocket backend server which stores and fetches package metadata in a Postgres database. Packages are stored in a dedicated IPFS network, and package metadata is indexed and stored in [forc.pub-index](https://github.com/FuelLabs/forc.pub-index).

The frontend uses React and TypeScript.

## Forc Documentation

For user documentation, including installing release builds, see: <https://docs.fuel.network/docs/forc/>.

## Building from Source

This section is for local development of `forc.pub`.

### Dependencies and Tools

`forc.pub` is built in Rust and TypeScript. To begin, install the Rust toolchain following instructions at <https://www.rust-lang.org/tools/install>. Then configure your Rust toolchain to use Rust `stable`:

```sh
rustup default stable
```

If not already done, add the Cargo bin directory to your `PATH` by adding the following line to `~/.profile` and restarting the shell session.

```sh
export PATH="${HOME}/.cargo/bin:${PATH}"
```

You will also need to install [Node.js](https://nodejs.org/en/learn/getting-started/how-to-install-nodejs).

To run the Postgres database locally, you will need [Docker](https://docs.docker.com/engine/install/).

To connect to the database, you will need the [Diesel CLI](https://diesel.rs/guides/getting-started).

Diesel is the Rust ORM used to create and run database migrations. It requires a separate C library called `libpq` to be installed as well.

```sh
# Mac only
brew install libpq

# Ubuntu only
apt-get install libpq5

# Install diesel CLI
cargo install diesel_cli --no-default-features --features postgres

# On macOS-arm64, you may need additional rust flags:
RUSTFLAGS='-L /opt/homebrew/opt/libpq/lib' cargo install diesel_cli --no-default-features --features postgres
```

It is also recommended to install a Postgres client like [DBeaver](https://dbeaver.io/) to connect and inspect the database while developing locally.

### Building the `forc.pub` server

Clone the repository and build the Sway toolchain:

```sh
git clone git@github.com:FuelLabs/forc.pub.git
cd forc.pub
cargo build
```

Confirm the server built successfully:

```sh
cargo run --bin forc.pub
```

### Running the `forc.pub` server

Before starting the server, the local database must be up and running.

```sh
./scripts/start_local_db.sh
```

Now we can run the server with:

```sh
cargo run
```

Alternatively, the server can be run locally with Docker, as it is in the deployed environment.

```sh
./scripts/start_local_server.sh

# Force the server image to be rebuilt
./scripts/start_local_server.sh -f
```

### Running the Frontend

The frontend requires npm and node to be installed.

```sh
cd app
npm i
npm start
```

This will open http://localhost:3000 in your browser. By default, it will use the local server endpoint, so the local server must be running.

## Contributing

We are not currently accepting contributions to `forc.pub` as the MVP is still being developed.
3 changes: 2 additions & 1 deletion app/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const SERVER_URI = process.env.REACT_APP_SERVER_URI ?? "http://localhost:8080"
export const SERVER_URI = process.env.REACT_APP_SERVER_URI ?? "http://localhost:8080";
export const REDIRECT_URI = process.env.REACT_APP_REDIRECT_URI ?? "http://localhost:3000";
3 changes: 2 additions & 1 deletion app/src/features/toolbar/components/UserButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useNavigate } from 'react-router-dom';
import { useGithubAuth } from '../hooks/useGithubAuth';
import { useLocalSession } from '../../../utils/localStorage';
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
import { REDIRECT_URI } from '../../../constants';

export const GITHUB_CLIENT_ID = 'Iv1.ebdf596c6c548759';

Expand Down Expand Up @@ -98,7 +99,7 @@ function UserButton() {
].join(',');

window.open(
`https://github.com/login/oauth/authorize?client_id=${GITHUB_CLIENT_ID}`,
`https://github.com/login/oauth/authorize?client_id=${GITHUB_CLIENT_ID}&redirect_uri=${REDIRECT_URI}`,
undefined,
windowDimensions
);
Expand Down
3 changes: 2 additions & 1 deletion app/src/features/toolbar/hooks/useGithubAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,13 @@ export function useGithubAuth(): [AuthenticatedUser | null, () => void] {
response.user && setGithubUser(response.user);
if (response.error) {
console.log('session error: ', response.error);
clearSessionId();
}
})
.catch((error) => {
console.log('Unexpected error: ', error);
});
}, [githubUser, sessionId, setGithubUser]);
}, [githubUser, sessionId, setGithubUser, clearSessionId]);

return [githubUser, logout];
}
2 changes: 1 addition & 1 deletion deployment/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ RUN cargo build
FROM ubuntu:22.04 as run

RUN apt-get update -y \
&& apt-get install -y --no-install-recommends ca-certificates curl git \
&& apt-get install -y --no-install-recommends ca-certificates curl git libpq5 \
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \
Expand Down
23 changes: 19 additions & 4 deletions scripts/start_local_db.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
#!/bin/bash

# Source environment variables
source .env
NETWORK_NAME="forc_pub_net"
CONTAINER_NAME="forc_pub_db"

# Check if Docker is installed
if ! command -v docker &> /dev/null; then
echo "Docker is not installed. Please install Docker to run this script."
exit 1
fi

# Check if the PostgreSQL container is already running
if docker ps --format '{{.Names}}' | grep -q '^postgres$'; then
if docker ps --format '{{.Names}}' | grep -q ^$CONTAINER_NAME$; then
echo "PostgreSQL container is already running."
exit 0
fi

# Source environment variables
source .env
# Create docker network if it does not exist
if [ -z $(docker network ls --filter name=^${NETWORK_NAME}$ --format="{{ .Name }}") ] ; then
echo "Creating docker network ${NETWORK_NAME}."
docker network create $NETWORK_NAME
fi

# Start PostgreSQL container
docker run --name $POSTGRES_USER -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD -e POSTGRES_DB=$POSTGRES_DB_NAME -d -p $POSTGRES_PORT:$POSTGRES_PORT postgres
docker run \
--rm -d \
--name $CONTAINER_NAME \
--network $NETWORK_NAME \
-e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
-e POSTGRES_DB=$POSTGRES_DB_NAME \
-p $POSTGRES_PORT:$POSTGRES_PORT \
postgres

echo "PostgreSQL container started successfully."
72 changes: 72 additions & 0 deletions scripts/start_local_server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/bin/bash

# Start the PostgreSQL container
./scripts/start_local_db.sh

# Source environment variables
source .env

CONTAINER_NAME="forc_pub_dev"
NETWORK_NAME="forc_pub_net"
DB_CONTAINER_NAME="forc_pub_db"
FORCE_REBUILD=false

# Check for command line arguments
while getopts "f" opt; do
case ${opt} in
f)
FORCE_REBUILD=true
;;
\?)
echo "Usage: $0 [-f]"
exit 1
;;
esac
done

# Check if Docker image exists
if $FORCE_REBUILD || [[ "$(docker images -q $DOCKER_IMAGE 2> /dev/null)" == "" ]]; then
echo "Building Docker image $DOCKER_IMAGE..."

# Build Docker image
docker build -t $CONTAINER_NAME -f deployment/Dockerfile .

# Check if build was successful
if [ $? -eq 0 ]; then
echo "Docker image $DOCKER_IMAGE built successfully."
else
echo "Failed to build Docker image $DOCKER_IMAGE."
exit 1
fi
else
echo "Docker image $DOCKER_IMAGE already exists. Use -f flag to force rebuild."
fi

# Remove the container if it exists
if [[ "$(docker ps -aqf name=$CONTAINER_NAME)" ]]; then
# Stop the container if it's running
if [[ "$(docker ps -q -f name=$CONTAINER_NAME)" ]]; then
echo "Stopping container $CONTAINER_NAME..."
docker stop $CONTAINER_NAME
if [ $? -eq 0 ]; then
echo "Container $CONTAINER_NAME stopped successfully."
else
echo "Failed to stop container $CONTAINER_NAME."
exit 1
fi
fi
fi

# Start the Docker container on the same network as the PostgreSQL container
docker run \
--rm -d \
--name $CONTAINER_NAME \
--network $NETWORK_NAME \
-p 8080:8080 \
-e POSTGRES_USER=$POSTGRES_USER \
-e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
-e POSTGRES_URI=$DB_CONTAINER_NAME \
-e POSTGRES_DB_NAME=$POSTGRES_DB_NAME \
$CONTAINER_NAME

echo "Server container started successfully."
13 changes: 10 additions & 3 deletions src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ impl Default for Database {
impl Database {
pub fn new() -> Self {
// Create a connection pool
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let pool = Pool::builder()
.build(ConnectionManager::<PgConnection>::new(database_url))
.build(ConnectionManager::<PgConnection>::new(db_url()))
.expect("db connection pool");

// Run migrations
Expand All @@ -53,3 +51,12 @@ impl Database {
pub(crate) fn string_to_uuid(s: String) -> Result<Uuid, DatabaseError> {
Uuid::parse_str(s.as_str()).map_err(|_| DatabaseError::InvalidUuid(s))
}

fn db_url() -> String {
dotenv().ok();
let user = env::var("POSTGRES_USER").expect("POSTGRES_USER must be set");
let password = env::var("POSTGRES_PASSWORD").expect("POSTGRES_PASSWORD must be set");
let uri = env::var("POSTGRES_URI").expect("POSTGRES_URI must be set");
let db_name = env::var("POSTGRES_DB_NAME").expect("POSTGRES_DB_NAME must be set");
format!("postgres://{user}:{password}@{uri}/{db_name}")
}
Loading