Skip to content

Commit

Permalink
Merge pull request #26 from Cron-Near/fix/rpc-config
Browse files Browse the repository at this point in the history
setup systemctl file generation
  • Loading branch information
TrevorJTClarke authored Dec 15, 2021
2 parents 1a6b2eb + b3c5368 commit 44de091
Showing 8 changed files with 132 additions and 23 deletions.
12 changes: 8 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ AGENT_ACCOUNT_ID=croncat-agent.near
AGENT_MIN_TASK_BALANCE=1
#NOTE: This is really only useful if the payout account is the same as the agent account
AGENT_AUTO_REFILL=false
AGENT_AUTO_RE_REGISTER=false

# Period between executing standard tasks, needs to be less than 60 seconds to be effective
WAIT_INTERVAL_MS=25000
@@ -29,7 +30,10 @@ HEARTBEAT_URL=
## Configure the following as CSV, in priority order, for RPC Failover
## -------------------------------------------------------------------
# Example: RPC_MAINNET_PROVIDERS="https://rpc.mainnet.near.org,http://localhost:3030"
RPC_MAINNET_PROVIDERS="https://rpc.mainnet.near.org"
RPC_TESTNET_PROVIDERS="https://rpc.testnet.near.org"
RPC_GUILDNET_PROVIDERS="https://rpc.openshards.io"
RPC_BETANET_PROVIDERS="https://rpc.betanet.near.org"
RPC_MAINNET_PROVIDERS="https://mainnet-rpc.openshards.io,https://rpc.mainnet.near.org"
RPC_TESTNET_PROVIDERS="https://rpc.testnet.near.org,https://testnet-rpc.openshards.io"
RPC_GUILDNET_PROVIDERS="https://rpc.openshards.io,https://guildnet-rpc.openshards.io"
RPC_BETANET_PROVIDERS="https://rpc.betanet.near.org"

## RPC API KEY for providers that require it
RPC_API_KEY=
50 changes: 45 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -18,13 +18,14 @@ For a list of up-to-date commands, run `croncat --help` in your terminal.
Usage: croncat <command> [options]

Commands:
croncat register <account_id> <payable_account_id> Add your agent to cron known agents
croncat update <account_id> <payable_account_id> Update your agent to cron known agents
croncat register <account_id> [payable_account_id] Add your agent to cron known agents
croncat update <account_id> [payable_account_id] Update your agent to cron known agents
croncat unregister <account_id> Account to remove from list of active agents.
croncat withdraw <account_id> Withdraw all rewards earned for this account
croncat status <account_id> Check agent status and balance for this account
croncat withdraw [account_id] Withdraw all rewards earned for this account
croncat status [account_id] Check agent status and balance for this account
croncat tasks Check how many tasks are currently available
croncat go <account_id> Run tasks that are available, if agent is registered and has balance
croncat go [account_id] Run tasks that are available, if agent is registered and has balance
croncat daemon [near_env] Generate a network specific croncat daemon service
```
## Docker Installation & Setup
@@ -86,6 +87,8 @@ AGENT_ACCOUNT_ID=YOUR_ACCOUNT.near
AGENT_MIN_TASK_BALANCE=1
# When balance is empty, will auto-withdraw rewards to cover signing txns, withdraws the payout account.
AGENT_AUTO_REFILL=true
# Helpful if your agent gets kicked after being inactive for any reason. Will attempt to re-register and become a pending agent upon next start.
AGENT_AUTO_RE_REGISTER=false
# The interval to wait between checking for tasks. Good intervals are below 60 seconds and above 10 seconds.
WAIT_INTERVAL_MS=450000
@@ -97,6 +100,43 @@ SLACK_CHANNEL=general
# If you have an external heartbeat service that just needs a ping (GET request)
HEARTBEAT=false
HEARTBEAT_URL=GET_REQUEST_URL_FOR_STATUS_SERVICE
## -------------------------------------------------------------------
## RPC Providers
## Configure the following as CSV, in priority order, for RPC Failover
## -------------------------------------------------------------------
# Example: RPC_MAINNET_PROVIDERS="https://rpc.mainnet.near.org,http://localhost:3030"
RPC_MAINNET_PROVIDERS="https://mainnet-rpc.openshards.io,https://rpc.mainnet.near.org"
RPC_TESTNET_PROVIDERS="https://rpc.testnet.near.org,https://testnet-rpc.openshards.io"
RPC_GUILDNET_PROVIDERS="https://rpc.openshards.io"
RPC_BETANET_PROVIDERS="https://rpc.betanet.near.org"
## RPC API KEY for providers that require it
RPC_API_KEY=
```
## Croncat Agent DAEMON
To setup an agent that has auto reboot capability, do the following steps:
```bash
# 1. create a service file via daemon command: Example for guildnet, use your desired network
croncat daemon guildnet
# 2. create the service symlink and then enable the service
sudo systemctl link ~/croncat/testnet/croncat_testnet.service
sudo systemctl enable croncat_testnet.service
# 3. reload systemctl
sudo systemctl daemon-reload
# 4. start the service
sudo systemctl start croncat_testnet.service
# 5. for accessing logs, you can use these commands, just make sure to use the right network name
journalctl -f -u croncat_testnet.service
tail -f /var/log/croncat_testnet.log
tail -f /var/log/croncaterror.log
```
## Development & Local Testing
17 changes: 17 additions & 0 deletions bin/croncat.js
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ const chalk = require('chalk')
const yargs = require('yargs')
import { utils } from 'near-api-js'
import getConfig from '../src/configuration'
import { createDaemonFile } from '../src/createSystemctl'
const { agentFunction, bootstrapAgent, runAgentTick, registerAgent } = require('../src/actions')

const AGENT_ACCOUNT_ID = process.env.AGENT_ACCOUNT_ID
@@ -117,6 +118,21 @@ const go = {
}
};

const daemon = {
command: 'daemon [near_env]',
desc: 'Generate a network specific croncat daemon service',
builder: (yargs) => yargs
.option('near_env', {
desc: 'NEAR_ENV',
type: 'string',
required: false
}),
handler: async options => {
const env = options.near_env || 'testnet'
await createDaemonFile(env)
}
};

const config = getConfig(process.env.NODE_ENV || 'development')
yargs // eslint-disable-line
.strict()
@@ -159,6 +175,7 @@ yargs // eslint-disable-line
.command(status)
.command(tasks)
.command(go)
.command(daemon)
.config(config)
.showHelpOnFail(true)
.recommendCommands()
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "croncat",
"version": "1.6.1",
"version": "1.6.3",
"description": "cron.cat CLI and Agent Runner",
"main": "src/index.js",
"scripts": {
12 changes: 8 additions & 4 deletions src/actions.js
Original file line number Diff line number Diff line change
@@ -15,15 +15,17 @@ export const WAIT_INTERVAL_MS = process.env.WAIT_INTERVAL_MS ? parseInt(`${proce
export const AGENT_ACCOUNT_ID = process.env.AGENT_ACCOUNT_ID || 'croncat-agent'
export const AGENT_MIN_TASK_BALANCE = utils.format.parseNearAmount(`${process.env.AGENT_MIN_TASK_BALANCE || '1'}`) // Default: 1_000_000_000_000_000_000_000_000 (1 NEAR)
export const AGENT_AUTO_REFILL = process.env.AGENT_AUTO_REFILL === 'true' ? true : false
export const AGENT_AUTO_RE_REGISTER = process.env.AGENT_AUTO_RE_REGISTER === 'true' ? true : false
export const BASE_GAS_FEE = 300000000000000
export const BASE_ATTACHED_PAYMENT = 0
export const BASE_REGISTER_AGENT_FEE = '4840000000000000000000'
let agentSettings = {}
let croncatSettings = {}

const slackProvider = new slack({ 'slackToken': process.env.SLACK_TOKEN })
const slackToken = process.env.SLACK_TOKEN || null
const slackProvider = new slack({ slackToken })
const notifySlack = text => {
if (process.env.SLACK_TOKEN) return slackProvider.send({
if (slackToken) return slackProvider.send({
slackChannel: process.env.SLACK_CHANNEL,
text
})
@@ -391,7 +393,9 @@ export async function bootstrapAgent(agentId, options) {
process.exit(0);
}
} catch (e) {
log(`No Agent: ${chalk.gray('Please register')}`)
// await registerAgent(agentId)
if (AGENT_AUTO_RE_REGISTER) {
log(`No Agent: ${chalk.gray('Attempting to register...')}`)
await registerAgent(agentId)
} else log(`No Agent: ${chalk.gray('Please register')}`)
}
}
24 changes: 16 additions & 8 deletions src/configuration.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
require('dotenv').config()

export const RPC_MAINNET = process.env.RPC_MAINNET_PROVIDERS ? process.env.RPC_MAINNET_PROVIDERS.split(',') : 'https://rpc.mainnet.near.org'
export const RPC_TESTNET = process.env.RPC_TESTNET_PROVIDERS ? process.env.RPC_TESTNET_PROVIDERS.split(',') : 'https://rpc.testnet.near.org'
export const RPC_GUILDNET = process.env.RPC_GUILDNET_PROVIDERS ? process.env.RPC_GUILDNET_PROVIDERS.split(',') : 'https://rpc.openshards.io'
export const RPC_BETANET = process.env.RPC_BETANET_PROVIDERS ? process.env.RPC_BETANET_PROVIDERS.split(',') : 'https://rpc.betanet.near.org'
export const RPC_MAINNET = process.env.RPC_MAINNET_PROVIDERS ? process.env.RPC_MAINNET_PROVIDERS.split(',') : ['https://rpc.mainnet.near.org']
export const RPC_TESTNET = process.env.RPC_TESTNET_PROVIDERS ? process.env.RPC_TESTNET_PROVIDERS.split(',') : ['https://rpc.testnet.near.org']
export const RPC_GUILDNET = process.env.RPC_GUILDNET_PROVIDERS ? process.env.RPC_GUILDNET_PROVIDERS.split(',') : ['https://rpc.openshards.io']
export const RPC_BETANET = process.env.RPC_BETANET_PROVIDERS ? process.env.RPC_BETANET_PROVIDERS.split(',') : ['https://rpc.betanet.near.org']
export const RPC_API_KEY = process.env.RPC_API_KEY ? process.env.RPC_API_KEY : null

const failoverRpcs = {
const rpcs = {
mainnet: RPC_MAINNET,
testnet: RPC_TESTNET,
guildnet: RPC_GUILDNET,
betanet: RPC_BETANET,
}

const headers = {}
if (RPC_API_KEY) headers['x-api-key'] = RPC_API_KEY

// allows configuration with defaults
const getRpcByNetworkId = id => {
return rpcs[id] && rpcs[id].length > 1 ? rpcs[id][0] : rpcs[id]
}

function getConfigByType(networkId, config) {
return {
// Cache of available RPC nodes for failover
// rpcNodes: failoverRpcs[networkId] || [],
networkId,
nodeUrl: networkId !== 'guildnet' ? `https://rpc.${networkId}.near.org` : 'https://rpc.openshards.io',
headers,
nodeUrl: getRpcByNetworkId(networkId),
explorerUrl: `https://explorer.${networkId === 'mainnet' ? '' : networkId + '.'}near.org`,
walletUrl: `https://wallet.${networkId === 'mainnet' ? '' : networkId + '.'}near.org`,
helperUrl: `https://helper.${networkId}.near.org`,
36 changes: 36 additions & 0 deletions src/createSystemctl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const path = require("path");
const { writeFileSync } = require("fs");

const generateDaemon = (env = 'testnet', user = 'near') => {
return `Description=CronCat ${env.toUpperCase()} Agent
After=multi-user.target
[Service]
Type=simple
User=${user}
WorkingDirectory=/home/${user}/croncat/${env}
ExecStart=/usr/bin/croncat go
StandardOutput=append:/var/log/croncat_${env}.log
StandardError=append:/var/log/croncat_${env}error.log
Restart=on-failure
RestartSec=60
KillSignal=SIGINT
TimeoutStopSec=45
KillMode=mixed
[Install]
WantedBy=multi-user.target`
}

export const createDaemonFile = async (env) => {
const _env = env || process.env.NEAR_ENV || 'testnet'
const user = require("os").userInfo().username
const daemon = generateDaemon(_env, user)

await writeFileSync(path.join(process.cwd(), `croncat_${_env}.service`), daemon)
}

// // NOTE: for testing
// ;(async () => {
// await createDaemonFile()
// })()
2 changes: 1 addition & 1 deletion src/slack.js
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ class Slack {
}

getHookUrl(options) {
if (!options || !options.slackToken) return
if (!options || !options.slackToken && !this.slackToken) return
const id = options.slackToken || this.slackToken
return `https://hooks.slack.com/services/${id}`
}

0 comments on commit 44de091

Please sign in to comment.