Skip to content

Commit

Permalink
Automatically deploy config.json (#14)
Browse files Browse the repository at this point in the history
* Update Readme with build status

* Automatically publish config

* Add config schema and checks
  • Loading branch information
noisekit authored May 16, 2023
1 parent b7dafb4 commit 756e9f7
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 22 deletions.
117 changes: 117 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
version: 2.1

parameters:
node-version:
type: string
default: '16.17.0'

commands:
npm-install:
steps:
- restore_cache:
keys:
- node_modules-{{ .Environment.CACHE_VERSION }}-{{ checksum "package-lock.json" }}
- node_modules-{{ .Environment.CACHE_VERSION }}-
- run: npm install
- save_cache:
key: node_modules-{{ .Environment.CACHE_VERSION }}-{{ checksum "package-lock.json" }}
paths:
- node_modules

ipfs-install:
steps:
- run:
name: 'Install IPFS'
command: |
LATEST_VERSION=$(curl -sSL https://dist.ipfs.tech/go-ipfs/versions | tail -n 1)
LATEST_VERSION_NUMBER=${LATEST_VERSION#*v}
DOWNLOAD_URL="https://dist.ipfs.tech/go-ipfs/${LATEST_VERSION}/go-ipfs_${LATEST_VERSION}_linux-amd64.tar.gz"
echo "DOWNLOAD_URL=$DOWNLOAD_URL"
curl -sSL -o ipfs.tar.gz $DOWNLOAD_URL
tar -xzf ipfs.tar.gz
sudo cp -f ./go-ipfs/ipfs /usr/local/bin/
ipfs init
ipfs-daemon:
steps:
- run:
name: 'Run IPFS Daemon'
command: ipfs daemon
background: true
- run:
name: 'Wait for IPFS Daemon to start'
command: wget --retry-connrefused --waitretry=20 --read-timeout=20 --timeout=15 -t 10 --post-data '' "http://localhost:5001/api/v0/version"

ipfs-deploy:
parameters:
source-path:
type: string
ipfs-api:
type: string
ipns-key:
type: string
ipfs-cluster-api:
type: string
steps:
- run:
name: 'Add to local IPFS node'
command: |
ipfs add --progress=true --pin=true --recursive "<< parameters.source-path >>"
- run:
name: 'Save IPFS_CID'
command: |
export IPFS_CID=$(ipfs add --progress=false --pin=true --recursive --quieter "<< parameters.source-path >>")
echo $IPFS_CID
echo "export IPFS_CID=$IPFS_CID" >> $BASH_ENV
- run:
name: 'Pin to the remote IPFS node'
command: curl --silent --request POST --user "$IPFS_USER:$IPFS_PASS" "<< parameters.ipfs-api >>/pin/add?recursive=true&progress=true&arg=$IPFS_CID"
- run:
name: 'Publish IPFS_CID to IPNS key << parameters.ipns-key >>'
command: curl --silent --request POST --user "$IPFS_USER:$IPFS_PASS" "<< parameters.ipfs-api >>/name/publish?key=<< parameters.ipns-key >>&arg=$IPFS_CID" | jq
- run:
name: 'Pin to Synthetix IPFS cluster'
command: curl --silent --request POST --user "$IPFS_USER:$IPFS_PASS" "<< parameters.ipfs-cluster-api >>/pin/add?arg=$IPFS_CID" | jq

jobs:
checks:
docker:
- image: cimg/node:<< pipeline.parameters.node-version >>
steps:
- checkout
- npm-install
- run: npm run lint:check
- run: npm run pretty:check
- run: npm run config:check

ipfs-deploy:
docker:
- image: cimg/node:<< pipeline.parameters.node-version >>
steps:
- checkout
- ipfs-install
- ipfs-daemon
- ipfs-deploy:
source-path: './config.json'
ipfs-api: 'https://ipfs.synthetix.io:5001/api/v0'
ipfs-cluster-api: 'https://ipfs.synthetix.io/api/v0'
ipns-key: 'synthetix-node-app-config'
- run:
name: 'Check if changes been made'
command: |
diff <(ipfs cat /ipns/k2k4r8jhn5r54sf708bnlxun971q0pteab82iw98544sj1e0hi3hp9q6) ./config.json
workflows:
version: 2.1

build:
jobs:
- checks

- ipfs-deploy:
requires: [checks]
filters:
branches:
only:
- master
- ipfs-deploy
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Synthetix Node

[![CircleCI](https://dl.circleci.com/status-badge/img/gh/Synthetixio/synthetix-node/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/Synthetixio/synthetix-node/tree/master)

![Synthetix Node](./synthetix-node.png)

The Synthetix ecosystem has been progressively moving towards reliance on ENS/IPFS over DNS/HTTP for web hosting. For example, Kwenta is available via [eth.limo](http://eth.limo) at [kwenta.eth.limo](https://kwenta.eth.limo), and you can access it directly in [Brave](https://brave.com) or [Opera](https://www.opera.com) at [kwenta.eth](http://kwenta.eth). Synthetix’s Core Contributors are also using IPFS to store and share protocol deployment data using [Cannon](https://usecannon.com).
Expand All @@ -17,41 +19,48 @@ Anyone with a computer and an internet connection can join the swarm. It’s fin
## Running the Node

On macOS, open your terminal and run the following command:

```sh
curl https://synthetixio.github.io/synthetix-node/install-macos.sh | bash
```

This will download the correct release of `SynthetixNode.app` to your Applications directory and start it.

### Manual Installation

Download the macOS app from the [Latest release page](https://github.com/Synthetixio/snx-node/releases/latest). (Windows and Linux versions are in development.) Select the ARM64 version if you are using a Mac with [Apple silicon](https://support.apple.com/en-us/HT211814).

Unzip and copy SynthetixNode to your Applications folder. There will be no pop-up to do so. Make sure to move it manually before proceeding to the next step.

Due to the latest MacOS security policies, it is no longer possible to execute unsigned apps. Therefore, you should clear the quarantine flag from the app before running it. Run the following command in terminal:

```sh
xattr -d com.apple.quarantine /Applications/SynthetixNode.app
```

### Build From Source Code

If you are concerned with security, clone this repository, review the implementation, and use the instructions below **Development** to start a development build.

If you would rather run this in a Docker container or run scripts manually, check out the [ipfs-follower repository](https://github.com/Synthetixio/ipfs-follower).

## Development

### Get Started

```sh
npm install
npm start
```

### Regenerate Electron app icons from svg

```sh
npm run iconsgen
```

### Releasing new version

```sh
pushd .
cd ./release/app
Expand All @@ -74,6 +83,7 @@ gh release upload $NEXT_VERSION ./release/build/*.zip
```

### Publishing new config

```sh
# 1. Ensure you have IPFS_USER and IPFS_PASS env vars set
export IPFS_USER=
Expand Down
13 changes: 11 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
"build:main": "NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
"build:renderer": "NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
"postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts",
"lint": "NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx",
"config:check": "ts-node ./src/config-check.ts ./config.json",
"lint": "eslint --fix .",
"lint:check": "eslint .",
"pretty": "prettier --write .",
"pretty:check": "prettier --check .",
"package": "ts-node ./.erb/scripts/clean.js dist && npm run build && CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder build --publish never",
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app",
"start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer",
Expand Down Expand Up @@ -48,7 +52,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tar": "^6.1.13",
"viem": "^0.3.1"
"viem": "^0.3.1",
"zod": "^3.21.4"
},
"devDependencies": {
"@electron/notarize": "^1.2.3",
Expand Down
4 changes: 4 additions & 0 deletions src/config-check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { ConfigSchema } from './config';
import config from '../config.json';

ConfigSchema.parse(config);
28 changes: 28 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { z } from 'zod';

export const DappSchema = z
.object({
id: z.string(),
label: z.string(),
icon: z.string(),
ens: z.string().optional(),
ipns: z.string().optional(),
qm: z.string().optional(),
bafy: z.string().optional(),
url: z.string().optional(),
})
.strict()
.refine((obj) => Boolean(obj.ens || obj.ipns), {
message: 'ens or ipns must be defined',
path: ['ens'],
});

export const DappsSchema = z.array(DappSchema);

export const ConfigSchema = z
.object({
dapps: DappsSchema,
})
.strict();

export type DappType = z.infer<typeof DappSchema>;
2 changes: 1 addition & 1 deletion src/main/dapps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { namehash, normalize } from 'viem/ens';
import * as contentHash from '@ensdomains/content-hash';
import { ipfs } from './ipfs';
import { getPid } from './pid';
import { DappType } from '../types';
import { DappType } from '../config';

Object.assign(global, { fetch });

Expand Down
10 changes: 7 additions & 3 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,12 @@ followerDaemon();
const followerCheck = setInterval(followerDaemon, 10_000);
app.on('will-quit', () => clearInterval(followerCheck));

ipcMain.handle('dapps', async () => DAPPS);
ipcMain.handle('dapps', async () => {
return DAPPS.map((dapp) => ({
...dapp,
url: dapp.url ? `http://${dapp.id}.localhost:8888` : null,
}));
});
ipcMain.handle('dapp', async (_event, id: string) => {
const dapp = DAPPS.find((dapp) => dapp.id === id);
return dapp && dapp.url ? `http://${dapp.id}.localhost:8888` : null;
Expand All @@ -317,8 +322,7 @@ const dappsResolver = setInterval(resolveAllDapps, 600_000); // 10 minutes
app.on('will-quit', () => clearInterval(dappsResolver));
waitForIpfs().then(resolveAllDapps).catch(logger.error);

const dappsCleaner = setInterval(cleanupOldDapps, 600_000);
// const dappsCleaner = setInterval(cleanupOldDapps, 600_000); // 10 minutes
const dappsCleaner = setInterval(cleanupOldDapps, 600_000); // 10 minutes
app.on('will-quit', () => clearInterval(dappsCleaner));
waitForIpfs().then(cleanupOldDapps).catch(logger.error);

Expand Down
2 changes: 1 addition & 1 deletion src/renderer/DApps/Dapps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from '@chakra-ui/react';
import { ExternalLinkIcon } from '@chakra-ui/icons';
import { useDapps } from './useDapps';
import { DappType } from '../../types';
import { DappType } from '../../config';

function DappButton({ dapp }: { dapp: DappType }) {
return (
Expand Down
5 changes: 2 additions & 3 deletions src/renderer/DApps/useDapps.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { useQuery } from '@tanstack/react-query';
import { DappType } from '../../types';
import { DappsSchema } from '../../config';

const { ipcRenderer } = window?.electron || {};

export function useDapps() {
return useQuery({
queryKey: ['dapps'],
queryFn: async () => {
const dapps = await ipcRenderer.invoke('dapps');
return dapps as DappType[];
return DappsSchema.parse(await ipcRenderer.invoke('dapps'));
},
initialData: () => [],
placeholderData: [],
Expand Down
10 changes: 0 additions & 10 deletions src/types.ts

This file was deleted.

Binary file modified synthetix-node.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 756e9f7

Please sign in to comment.