The Wayback Machine - http://web.archive.org/web/20230109074828/https://github.com/nextzlog/ats4
Skip to content

nextzlog/ats4

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
app
Jan 8, 2023
Nov 27, 2021
Jul 31, 2022
Jul 14, 2022
Apr 2, 2017
Jan 9, 2023
Jan 8, 2023

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 following command into the terminal and run it:

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
    - ./ats.conf:/ats/conf/ats.conf
    - ./rules.rb:/ats/conf/rules.rb
    command: /ats/bin/ats4
  www:
    image: nginx:latest
    ports:
    - 80:80
    volumes:
    - ./proxy.conf:/etc/nginx/conf.d/default.conf
EOS

echo -n 'enter mail hostname: '
read host

echo -n 'enter mail username: '
read user

echo -n 'enter mail password: '
read pass

cat << EOS > ats.conf
play.mailer.host=$host
play.mailer.port=465
play.mailer.ssl=true
play.mailer.user="$user"
play.mailer.password="$pass"
play.mailer.mock=false
ats4.rules=rules.rb
EOS

cat << EOS > rules.rb
require 'rules/sample/plain'
RULE
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;
    }
    location ~ /admin {
      allow 127.0.0.1;
      deny all;
    }
  }
}
EOS

docker compose up -d

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
    - ./ats.conf:/ats/conf/ats.conf
    - ./rules.rb:/ats/conf/rules.rb
    command: /ats/bin/ats4
  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;
    }
    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

Create the system configuration file ats.conf as follows:

# Typesafe Mailer Plugin
play.mailer.host=mail.allja1.org
play.mailer.port=465
play.mailer.ssl=true
play.mailer.user="***********"
play.mailer.password="*******"

# Never forget to disable mock mode before the contest:
play.mailer.mock=true

Modify the settings properly.

Regulation

Add the path to the contest definition file to ats.conf like this:

# Contest
# ats4.rules=/rules/JA1ZLO/ja1.rb
# ats4.rules=/rules/JA1ZGP/uec.rb
ats4.rules=rules.rb

In addition, create rules.rb as follows:

require 'rules/sample/plain'
RULE

Of course, you can also modify rules.rb to customize it for your contest. See plain.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 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:

ATS-4

Streaming Demo

">
<!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/.