ATS-4 is an Automatic Acceptance & Tabulation System for Amateur-Radio Contests, based on QxSL. Feel free to visit ALLJA1 ATS-4.
- provides a web interface for contest-log acceptance.
- verifies the uploaded logs according to the contest rules implemented in Ruby.
- supports many contests including UEC, ALLJA1, REAL-TIME, VUS, QRP, AREA-1 AM, etc.
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 -dThen, point your browser to http://localhost and verify that ATS-4 is running.
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.confThen, follow the instructions below.
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.
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: falseModify the settings properly.
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.rbOf course, you can specify different rules by mounting external Ruby files into the container.
See ats.rb for example.
Finally, create a container as follows:
$ docker compose up -dAccess 80 port of the container.
Stop and remove the container as follows:
$ docker compose downPull the latest image as follows:
$ docker pull ghcr.io/nextzlog/ats4:masterYou can change Scala code and configuration without restarting by starting ATS-4 in development mode as follows:
$ sbt runThen, 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.
ATS-4 provides the streaming API for the REAL-TIME CONTEST.
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>.
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.
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}
]
}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);
}Feel free to make issues at nextzlog/todo. Follow @nextzlog on Twitter.
- JG1VPP
- JJ2ULU
- JH1GEB
- JE6MDL
- JO4EFC
- JJ1IBY
- JS2FVO
-
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/.