Skip to content

Commit

Permalink
feat: implement base code structure (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsutsu3 authored Dec 1, 2024
1 parent dad5e9a commit 00c1fff
Show file tree
Hide file tree
Showing 32 changed files with 2,634 additions and 143 deletions.
16 changes: 11 additions & 5 deletions .env
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Unbound Configuration Path
# Select one of the following options:
# - unix: Unix Domain Socket
# - tls: TLS Socket
UNBOUND_CONF_PATH=./unbound-config/unix
# UNBOUND_CONF_PATH=./unbound-config/tls
# default: ./unbound-config/unix
# UNBOUND_CONF_PATH=./unbound-config/unix
# UNBOUND_CONF_PATH=./unbound-config/tls

# Unbound Version
# default: latest
# UNBOUND_VERSION=latest

# Unbound DNS, Control Port
# UNBOUND_DNS_PORT=53
# UNBOUND_CONTROL_PORT=8953
12 changes: 12 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Unbound Configuration Path
# default: ./unbound-config/unix
# UNBOUND_CONF_PATH=./unbound-config/unix
# UNBOUND_CONF_PATH=./unbound-config/tls

# Unbound Version
# default: latest
# UNBOUND_VERSION=latest

# Unbound DNS, Control Port
# UNBOUND_DNS_PORT=53
# UNBOUND_CONTROL_PORT=8953
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,43 @@ jobs:
run: npm ci
- name: Lint with ESLint
run: npm run lint
generate-certs:
name: Generate Certs
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install OpenSSL
run: sudo apt-get install -y openssl
- name: Generate server key
run: |
openssl genrsa -out tests/key/unbound_server.key 2048
openssl req -new -key tests/key/unbound_server.key -out tests/key/unbound_server.csr -subj "/CN=server"
openssl x509 -req -in tests/key/unbound_server.csr -signkey tests/key/unbound_server.key -out tests/key/unbound_server.pem -days 365
- name: Generate client key
run: |
openssl genrsa -out tests/key/unbound_control.key 2048
openssl req -new -key tests/key/unbound_control.key -out tests/key/unbound_control.csr -subj "/CN=client"
openssl x509 -req -in tests/key/unbound_control.csr -signkey tests/key/unbound_control.key -out tests/key/unbound_control.pem -days 365
- name: Upload generated keys
uses: actions/upload-artifact@v4
with:
name: test-keys
path: tests/key/
test:
name: Test
needs: generate-certs
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x, 20.x, 22.x]
steps:
- uses: actions/checkout@v4
- name: Download generated keys
uses: actions/download-artifact@v4
with:
name: test-keys
path: tests/key/
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
Expand Down
92 changes: 92 additions & 0 deletions .github/workflows/it.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# TODO: Fix Unix domain socket permissions

# name: Test Unbound with Multiple Versions

# on:
# push:
# branches:
# - main
# pull_request:
# branches:
# - main

# jobs:
# test-unbound:
# runs-on: ubuntu-latest

# strategy:
# matrix:
# include:
# # TODO: Multiple versions of Unbound can be tested by adding more versions here.
# # - fix: unbound.conf, test file's socket path
# # - unbound-version: 1.18.0
# # unbound-port: 5318
# # unbound-control-port: 8918
# # - unbound-version: 1.19.3
# # unbound-port: 5319
# # unbound-control-port: 8919
# # - unbound-version: 1.20.0
# # unbound-port: 5320
# # unbound-control-port: 8920
# # - unbound-version: 1.21.1
# # unbound-port: 5321
# # unbound-control-port: 8921
# - unbound-version: 1.22.0
# unbound-port: 5322
# unbound-control-port: 8922

# steps:
# - uses: actions/checkout@v4

# - name: Set up Docker Compose
# run: sudo apt-get update && sudo apt-get install -y docker-compose

# - name: Start Unbound containers
# run: |
# UNBOUND_VERSION=${{ matrix.unbound-version }} \
# UNBOUND_DNS_PORT=${{ matrix.unbound-port }} \
# UNBOUND_CONTROL_PORT=${{ matrix.unbound-control-port }} \
# docker-compose up -d
# - name: Verify Unbound is running
# run: docker ps

# - name: Wait for Unbound to become healthy
# run: |
# echo "Waiting for Unbound to be ready..."
# for i in {1..30}; do
# HEALTH=$(docker inspect --format='{{.State.Health.Status}}' unbound-${{ matrix.unbound-version }})
# if [ "$HEALTH" == "healthy" ]; then
# echo "Unbound is healthy!"
# break
# fi
# echo "Unbound is not ready yet. Waiting..."
# sleep 2
# done
# if [ "$HEALTH" != "healthy" ]; then
# echo "Unbound did not become healthy in time."
# exit 1
# fi

# - name: Fix permissions inside container
# run: |
# docker exec unbound-${{ matrix.unbound-version }} chmod 777 /opt/unbound/etc/unbound/socket/unbound.ctl

# - name: Set permissions for Unix socket
# run: ls -Rl "$GITHUB_WORKSPACE/unbound-config"

# - name: Test Unbound
# run: |
# dig @localhost -p ${{ matrix.unbound-port }} example.com

# - name: Use Node.js 22.x
# uses: actions/setup-node@v4
# with:
# node-version: 22.x

# - name: Install dependencies
# run: npm ci
# - run: npm run test:it

# - name: Stop Unbound
# run: |
# docker compose stop unbound-${{ matrix.unbound-version }}
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,10 @@ dist-ssr


coverage/
unbound-config/*
!unbound-config/unbound.conf
unbound-config/*/*
!unbound-config/tls/unbound.conf
!unbound-config/unix/unbound.conf
tests/__snapshots__
tests/key/*
!.gitkeep
.env
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
"editor.formatOnSave": true,
"editor.formatOnType": true,
"editor.formatOnPaste": true,
"files.eol": "\n"
"files.eol": "\n",
"jest.runMode": {
"type": "on-demand"
}
}
67 changes: 56 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,23 +89,69 @@ yarn add unbound-control-ts

Here's a basic example to demonstrate how to use the library:

Use domain socket:
```ts
import { UnboundControl } from 'unbound-control-ts';
import { UnixUnboundClient } from 'unbound-control-ts';

// Initialize the client with the path to the unbound-control binary
const unbound = new UnboundControl('/path/to/unbound-control');
const client = new UnixUnboundClient('/path/to/unbound-control.sock');

// Fetch and display Unbound statistics
async function getStats() {
(async () => {
try {
const stats = await unbound.stats();
console.log('Unbound Statistics:', stats);
const response = await client.status();
console.log(response);
} catch (error) {
console.error('Error fetching stats:', error);
if (error instanceof UnboundError) {
console.error(error.message);
} else {
console.error(error);
}
}
}
})();
```

Use tcp socket:
```ts
import { TcpUnboundClient } from 'unbound-control-ts';

const client = new TcpUnboundClient('localhost', 8953);

getStats();
(async () => {
try {
const response = await client.status();
console.log(response);
} catch (error) {
if (error instanceof UnboundError) {
console.error(error.message);
} else {
console.error(error);
}
}
})();
```

output:

```json
{
"json": {
"modules": [
"subnetcache",
"validator",
"iterator",
],
"options": [
"reuseport",
"control(namedpipe)",
],
"pid": 1,
"status": "running",
"threads": 1,
"uptime": 292,
"verbosity": 1,
"version": "1.22.0",
},
"raw": "version: 1.22.0\nverbosity: 1\nthreads: 1\nmodules: 3 [ subnetcache validator iterator ]\nuptime: 292 seconds\noptions: reuseport control(namedpipe)\nunbound (pid 1) is running...\n",
}
```

## Development
Expand All @@ -117,7 +163,6 @@ Before you begin, ensure you have the following tools installed on your system:
- **Node.js**: Version 16 or later. [Download Node.js](https://nodejs.org/)
- **npm**: Comes with Node.js, or install it separately if needed.
- **Unbound**: Ensure that `unbound-control` is installed and properly configured. Follow the [Unbound installation guide](https://nlnetlabs.nl/documentation/unbound/) for details.
- **TypeScript**: (Optional) For contributing to or extending the library, TypeScript must be installed globally or as a dev dependency.

### Develop Setup

Expand Down
63 changes: 32 additions & 31 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
services:
unbound-setup:
image: mvance/unbound:latest
volumes:
- ${UNBOUND_CONF_PATH}:/opt/unbound/etc/unbound
restart: "no"
entrypoint: []
command: >-
/bin/sh -c "
if [ ! -f /opt/unbound/etc/unbound/key/unbound_server.key ]; then
echo 'Setup start' &&
unbound-control-setup &&
mkdir /opt/unbound/etc/unbound/key &&
mv /opt/unbound/etc/unbound/unbound_* /opt/unbound/etc/unbound/key &&
echo 'Setup complete';
else
echo 'Certificates already exist';
fi
"
unbound:
image: mvance/unbound:latest
container_name: unbound
ports:
- "53:53/tcp"
- "53:53/udp"
- "8953:8953"
volumes:
- ${UNBOUND_CONF_PATH}:/opt/unbound/etc/unbound
restart: unless-stopped
depends_on:
- unbound-setup
services:
unbound-setup:
image: mvance/unbound:${UNBOUND_VERSION:-latest}
volumes:
- ${UNBOUND_CONF_PATH:-./unbound-config/unix}:/opt/unbound/etc/unbound
restart: "no"
entrypoint: []
command: >-
/bin/sh -c "
if [ ! -f /opt/unbound/etc/unbound/key/unbound_server.key ]; then
echo 'Setup start' &&
unbound-control-setup &&
mkdir /opt/unbound/etc/unbound/key /opt/unbound/etc/unbound/socket &&
mv /opt/unbound/etc/unbound/unbound_* /opt/unbound/etc/unbound/key &&
chown 1000 /opt/unbound/etc/unbound/key/* &&
echo 'Setup complete';
else
echo 'Certificates already exist';
fi
"
unbound:
image: mvance/unbound:${UNBOUND_VERSION:-latest}
container_name: unbound-${UNBOUND_VERSION:-latest}
ports:
- "${UNBOUND_DNS_PORT:-53}:53/tcp"
- "${UNBOUND_DNS_PORT:-53}:53/udp"
- "${UNBOUND_CONTROL_PORT:-8953}:8953"
volumes:
- ${UNBOUND_CONF_PATH:-./unbound-config/unix}:/opt/unbound/etc/unbound
restart: unless-stopped
depends_on:
- unbound-setup
41 changes: 38 additions & 3 deletions examples/index.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,39 @@
const { hello } = require("../../dist/index.cjs");
const path = require("path");
const { UnboundControlClient, UnboundError } = require("../dist/index.cjs");

const result = hello();
console.log(`CJS Result: ${result}`);
const baseDir = path.resolve(__dirname, "..");

const unixSocketName = path.join(
baseDir,
"unbound-config/unix/socket/unbound.ctl",
);

const client = new UnboundControlClient(unixSocketName);

(async () => {
try {
const response = await client.status();
console.log(response.raw);
console.log(response.json);
} catch (error) {
if (error instanceof UnboundError) {
console.error(error.message);
} else {
console.error(error);
}
}
})();

(async () => {
try {
const response = await client.status();
console.log(response.raw);
console.log(response.json);
} catch (error) {
if (error instanceof UnboundError) {
console.error(error.message);
} else {
console.error(error);
}
}
})();
Loading

0 comments on commit 00c1fff

Please sign in to comment.