Skip to content

Commit

Permalink
Merge pull request #5 from FuelLabs/sophie/docker-libpq
Browse files Browse the repository at this point in the history
Add libpq to docker image, add script and readme
  • Loading branch information
sdankel committed Apr 26, 2024
2 parents e7056a2 + 4b7d739 commit b964b49
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 14 deletions.
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}")
}

0 comments on commit b964b49

Please sign in to comment.