nextzlog / ats4

automatic acceptance & tabulation system for amateur radio contests

Home Page:https://nextzlog.dev/ats4

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ATS-4: Amateur-Radio Contest Administration System

image image image image image image badge

ATS-4 is an Automatic Acceptance & Tabulation System for Amateur-Radio Contests, based on QxSL. Feel free to visit ALLJA1 ATS-4.

Features

  • provides a web interface for contest-log acceptance.
  • verifies the uploaded logs according to the contest rules described in Ruby or LISP forms.
  • supports many contests including UEC, ALLJA1, REAL-TIME, 1-Area 6m AM and TAMAGAWA.

Documents

Quick Start

Docker image is available. Paste the entire following script into the terminal and run it.

echo -n 'enter mail hostname: '
read host

echo -n 'enter mail username: '
read user

echo -n 'enter mail password: '
read pass

cat << EOS > docker-compose.yaml
version: '3'
services:
  ATS4:
    image: ghcr.io/nextzlog/ats4:master
    ports:
    - 9000:9000
    volumes:
    - ./ats/data:/ats/data
    - ./ats/logs:/ats/logs
    command: /ats/bin/ats4
    environment:
      TZ: Asia/Tokyo
      ATS4_MAIL_HOST: $host
      ATS4_MAIL_USER: $user
      ATS4_MAIL_PASS: $pass
      ATS4_MAIL_MOCK: false
      ATS4_RULE_FILE: /rules/ats.rb
  www:
    image: nginx:latest
    ports:
    - 80:80
    volumes:
    - ./proxy.conf:/etc/nginx/conf.d/default.conf
EOS

echo -n 'enter server domain: '
read name

cat << EOS > proxy.conf
server {
  server_name $name;
  location / {
    proxy_pass http://ATS4:9000;
    location ~ /admin {
      allow 127.0.0.1;
      deny all;
    }
  }
}
EOS

docker compose up -d

Then, point your browser to http://localhost and verify that ATS-4 is running.

Configuration

First, create docker-compose.yaml as follows:

version: '3'
services:
  ATS4:
    image: ghcr.io/nextzlog/ats4:master
    ports:
    - 9000:9000
    volumes:
    - ./ats/data:/ats/data
    - ./ats/logs:/ats/logs
    command: /ats/bin/ats4
    environment:
      TZ: Asia/Tokyo
      ATS4_MAIL_HOST: $host
      ATS4_MAIL_USER: $user
      ATS4_MAIL_PASS: $pass
      ATS4_MAIL_MOCK: false
      ATS4_RULE_FILE: /rules/ats.rb
  www:
    image: nginx:latest
    ports:
    - 80:80
    volumes:
    - ./proxy.conf:/etc/nginx/conf.d/default.conf

Then, follow the instructions below.

Proxy

Create proxy.conf as follows:

server {
  server_name localhost;
  location / {
    proxy_pass http://ATS4:9000;
    location ~ /admin {
      allow 127.0.0.1;
      deny all;
    }
  }
}

Make sure that unauthorized clients cannot access administration pages under /admin. Expose port 80 of the container to the internet so that the administration page cannot be accessed.

Email

Configure environment variables in docker-compose.yaml as follows:

environment:
  ATS4_MAIL_HOST: $host
  ATS4_MAIL_USER: $user
  ATS4_MAIL_PASS: $pass
  ATS4_MAIL_MOCK: false

Modify the settings properly.

Regulation

Configure environment variables in docker-compose.yaml as follows:

environment:
  ATS4_RULE_FILE: /rules/ats.rb
# ATS4_RULE_FILE: /rules/1am.rb
# ATS4_RULE_FILE: /rules/ja1.rb
# ATS4_RULE_FILE: /rules/uec.rb

Of course, you can specify different rules by mounting external Ruby files into the container. See ats.rb for example.

Run

Finally, create a container as follows:

$ docker compose up -d

Access 80 port of the container.

Shutdown

To kill the container, enter the following command:

$ docker compose kill

Development Mode

You can change Scala code and configuration without restarting by starting ATS-4 in development mode as follows:

$ sbt run

Then, access http://localhost:9000/admin/shell to develop contest rules interactively. You can test the scoring algorithm by attaching QSO data to the web form.

Stream API

ATS-4 provides the streaming API for the REAL-TIME CONTEST.

Registration

Contest participants will register their account information with ATS-4 in advance. ATS-4 returns a security key (UUID) by sending a GET request to http://localhost:8873?id=<UUID>. Clients may retrieve the key by listening on the 8873 port and access /agent/<UUID>.

Upstream

When the contest starts, the client always connects to the server via WebSocket. Each time a participant contacts another participant on air, the client sends the difference in the QSO records to the server. Messages from the clients to the server must follow the format below.

position field
1st byte number of QSOs deleted
sequence header of the QSO data
sequence QSO entities to delete
sequence QSO entities to append

The second and subsequent bytes of the messages are formatted as a single electronic log file. The format must be officially supported by the QXSL library.

Downstream

The server receives the QSO records, scores it, wait a few seconds, and then notifies all clients of the score update. JSON messages from the server to the clients are formatted as follows:

{
  "14MHz": [
    {"call": "JA1ZLO", "score": 200, "total": 2200},
    {"call": "JA1YWX", "score": 100, "total": 2100}
  ]
}

Demonstration

A simple WebSocket client for ATS-4 may be written as follows:

<!DOCTYPE html>
<html lang='ja'>
  <head>
    <title>ATS-4</title>
    <script type="application/javascript" src="client.js"></script>
  </head>
  <body>
    <h1>Streaming Demo</h1>
    <textarea cols='160' rows='30' id='QSOs'></textarea>
    <p>
      <label>Delete <input type='number' id='trim' min='0' max='255' value='0'>QSOs,</label>
      <label>Submission Key: <input type='text' id='UUID' placeholder='/agent/UUID'></label>
      <button type='button' onclick='access();'>Access</button>
      <button type='button' onclick='submit();'>Submit</button>
    </p>
    <div id='messages'></div>
  </body>
</html>

The JavaScript program referenced may be written as follows:

let sock;
function access() {
  const uuid = document.getElementById('UUID').value;
  sock = new WebSocket('ws://localhost:9000' + uuid);
  sock.binaryType = 'arraybuffer';
  sock.onmessage = function(msg) {
    const decoder = new TextDecoder();
    const data = decoder.decode(new Uint8Array(msg.data));
    const text = document.createTextNode(data);
    const node = document.createElement('div');
    document.getElementById('messages').appendChild(node);
    node.appendChild(text);
  };
}
function submit() {
  const encoder = new TextEncoder();
  const QSOs = document.getElementById('QSOs').value;
  const trim = document.getElementById('trim').value;
  const data = new TextEncoder().encode(QSOs);
  const full = new (data.constructor)(data.length + 1);
  full[0] = parseInt(trim);
  full.set(data, 1);
  sock.send(full);
}

Contribution

Feel free to make issues at nextzlog/todo. Follow @nextzlog on Twitter.

License

Author

無線部開発班

  • JG1VPP
  • JJ2ULU
  • JH1GEB
  • JE6MDL
  • JO4EFC
  • JJ1IBY
  • JS2FVO

Clauses

  • This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

  • This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU General Public License for more details.

  • You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

About

automatic acceptance & tabulation system for amateur radio contests

https://nextzlog.dev/ats4

License:GNU General Public License v3.0


Languages

Language:Scala 45.6%Language:HTML 41.9%Language:Ruby 11.5%Language:CSS 0.7%Language:Dockerfile 0.4%