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 described in Ruby or LISP forms.
- supports many contests including UEC, ALLJA1, REAL-TIME, 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 -d
Then, 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.conf
Then, 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: false
Modify 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.rb
Of 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 -d
Access 80 port of the container.
Stop and remove the container as follows:
$ docker compose down
Pull the latest image as follows:
$ docker pull ghcr.io/nextzlog/ats4:master
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.
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/.