kryten-moderator 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kryten_moderator-0.1.0/INSTALL.md +212 -0
- kryten_moderator-0.1.0/LICENSE +21 -0
- kryten_moderator-0.1.0/PKG-INFO +123 -0
- kryten_moderator-0.1.0/README.md +96 -0
- kryten_moderator-0.1.0/kryten_moderator/__init__.py +22 -0
- kryten_moderator-0.1.0/kryten_moderator/__main__.py +81 -0
- kryten_moderator-0.1.0/kryten_moderator/config.py +42 -0
- kryten_moderator-0.1.0/kryten_moderator/service.py +74 -0
- kryten_moderator-0.1.0/pyproject.toml +73 -0
- kryten_moderator-0.1.0/systemd/README.md +57 -0
- kryten_moderator-0.1.0/systemd/kryten-moderator.service +28 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Installation Guide
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
- Python 3.10 or higher
|
|
6
|
+
- Poetry (Python package manager)
|
|
7
|
+
- NATS server (running and accessible)
|
|
8
|
+
- Git
|
|
9
|
+
|
|
10
|
+
## Quick Start
|
|
11
|
+
|
|
12
|
+
### 1. Clone the Repository
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
git clone https://github.com/grobertson/kryten-moderator.git
|
|
16
|
+
cd kryten-moderator
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. Install Dependencies
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
poetry install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 3. Configure the Service
|
|
26
|
+
|
|
27
|
+
Copy the example configuration:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cp config.example.json config.json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Edit `config.json` with your settings:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"nats_url": "nats://localhost:4222",
|
|
38
|
+
"nats_subject_prefix": "cytube",
|
|
39
|
+
"service_name": "kryten-moderator"
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 4. Run the Service
|
|
44
|
+
|
|
45
|
+
**Development mode:**
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
poetry run kryten-moderator --config config.json --log-level DEBUG
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Using startup script (PowerShell):**
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
.\start-moderator.ps1
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Using startup script (Bash):**
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
./start-moderator.sh
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Production Installation
|
|
64
|
+
|
|
65
|
+
### System User Setup
|
|
66
|
+
|
|
67
|
+
Create a dedicated system user:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
sudo useradd -r -s /bin/false -d /opt/kryten-moderator kryten
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Installation Directory
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
sudo mkdir -p /opt/kryten-moderator
|
|
77
|
+
sudo chown kryten:kryten /opt/kryten-moderator
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Configuration Directory
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
sudo mkdir -p /etc/kryten/moderator
|
|
84
|
+
sudo chown kryten:kryten /etc/kryten/moderator
|
|
85
|
+
sudo cp config.example.json /etc/kryten/moderator/config.json
|
|
86
|
+
sudo chown kryten:kryten /etc/kryten/moderator/config.json
|
|
87
|
+
sudo chmod 600 /etc/kryten/moderator/config.json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Edit the configuration:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
sudo nano /etc/kryten/moderator/config.json
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Log Directory
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
sudo mkdir -p /var/log/kryten-moderator
|
|
100
|
+
sudo chown kryten:kryten /var/log/kryten-moderator
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Install Application
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
cd /opt/kryten-moderator
|
|
107
|
+
sudo -u kryten git clone https://github.com/grobertson/kryten-moderator.git .
|
|
108
|
+
sudo -u kryten poetry install --no-dev
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Systemd Service
|
|
112
|
+
|
|
113
|
+
Install the systemd service:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
sudo cp systemd/kryten-moderator.service /etc/systemd/system/
|
|
117
|
+
sudo systemctl daemon-reload
|
|
118
|
+
sudo systemctl enable kryten-moderator
|
|
119
|
+
sudo systemctl start kryten-moderator
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Check service status:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
sudo systemctl status kryten-moderator
|
|
126
|
+
sudo journalctl -u kryten-moderator -f
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Updating
|
|
130
|
+
|
|
131
|
+
### Development
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
git pull
|
|
135
|
+
poetry install
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Production
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
cd /opt/kryten-moderator
|
|
142
|
+
sudo systemctl stop kryten-moderator
|
|
143
|
+
sudo -u kryten git pull
|
|
144
|
+
sudo -u kryten poetry install --no-dev
|
|
145
|
+
sudo systemctl start kryten-moderator
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Troubleshooting
|
|
149
|
+
|
|
150
|
+
### Check NATS Connection
|
|
151
|
+
|
|
152
|
+
Ensure NATS server is running:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Check if NATS is listening
|
|
156
|
+
netstat -tuln | grep 4222
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### View Logs
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Systemd service logs
|
|
163
|
+
sudo journalctl -u kryten-moderator -f
|
|
164
|
+
|
|
165
|
+
# Check for errors
|
|
166
|
+
sudo journalctl -u kryten-moderator --since "1 hour ago" | grep -i error
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Test Configuration
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# Validate JSON syntax
|
|
173
|
+
python -m json.tool config.json
|
|
174
|
+
|
|
175
|
+
# Test connection manually
|
|
176
|
+
poetry run kryten-moderator --config config.json --log-level DEBUG
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Permissions Issues
|
|
180
|
+
|
|
181
|
+
Ensure correct ownership:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
sudo chown -R kryten:kryten /opt/kryten-moderator
|
|
185
|
+
sudo chown -R kryten:kryten /etc/kryten/moderator
|
|
186
|
+
sudo chown -R kryten:kryten /var/log/kryten-moderator
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Uninstalling
|
|
190
|
+
|
|
191
|
+
### Stop and Disable Service
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
sudo systemctl stop kryten-moderator
|
|
195
|
+
sudo systemctl disable kryten-moderator
|
|
196
|
+
sudo rm /etc/systemd/system/kryten-moderator.service
|
|
197
|
+
sudo systemctl daemon-reload
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Remove Files
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
sudo rm -rf /opt/kryten-moderator
|
|
204
|
+
sudo rm -rf /etc/kryten/moderator
|
|
205
|
+
sudo rm -rf /var/log/kryten-moderator
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Remove User
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
sudo userdel kryten
|
|
212
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kryten Robot Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kryten-moderator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Kryten moderation service - handles chat moderation and filtering
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: cytube,moderation,chat,nats,microservices
|
|
8
|
+
Author: Kryten Robot Team
|
|
9
|
+
Requires-Python: >=3.10,<4.0
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Communications :: Chat
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Dist: kryten-py (>=0.6.0,<0.7.0)
|
|
22
|
+
Project-URL: Documentation, https://github.com/grobertson/kryten-moderator/blob/main/README.md
|
|
23
|
+
Project-URL: Homepage, https://github.com/grobertson/kryten-moderator
|
|
24
|
+
Project-URL: Repository, https://github.com/grobertson/kryten-moderator
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
"# Kryten Moderator
|
|
28
|
+
|
|
29
|
+
Kryten moderation service - handles chat moderation and filtering for CyTube.
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- Real-time chat message monitoring
|
|
34
|
+
- User tracking and management
|
|
35
|
+
- Event-driven architecture using NATS
|
|
36
|
+
- Extensible moderation rules
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
### Prerequisites
|
|
41
|
+
|
|
42
|
+
- Python 3.10 or higher
|
|
43
|
+
- Poetry
|
|
44
|
+
- NATS server running
|
|
45
|
+
- kryten-py library
|
|
46
|
+
|
|
47
|
+
### Setup
|
|
48
|
+
|
|
49
|
+
1. Install dependencies:
|
|
50
|
+
```bash
|
|
51
|
+
poetry install
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
2. Copy the example configuration:
|
|
55
|
+
```bash
|
|
56
|
+
cp config.example.json config.json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
3. Edit `config.json` with your settings:
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"nats_url": "nats://localhost:4222",
|
|
63
|
+
"nats_subject_prefix": "cytube",
|
|
64
|
+
"service_name": "kryten-moderator"
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Usage
|
|
69
|
+
|
|
70
|
+
### Running the Service
|
|
71
|
+
|
|
72
|
+
Using Poetry:
|
|
73
|
+
```bash
|
|
74
|
+
poetry run kryten-moderator --config config.json
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Using the startup script (PowerShell):
|
|
78
|
+
```powershell
|
|
79
|
+
.\start-moderator.ps1
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Using the startup script (Bash):
|
|
83
|
+
```bash
|
|
84
|
+
./start-moderator.sh
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Command Line Options
|
|
88
|
+
|
|
89
|
+
- `--config PATH`: Path to configuration file (default: `/etc/kryten/moderator/config.json`)
|
|
90
|
+
- `--log-level LEVEL`: Set logging level (DEBUG, INFO, WARNING, ERROR)
|
|
91
|
+
|
|
92
|
+
## Event Handling
|
|
93
|
+
|
|
94
|
+
The service currently listens for:
|
|
95
|
+
|
|
96
|
+
- **chatMsg**: Chat messages from users
|
|
97
|
+
- **addUser**: User join events
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
### Running Tests
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
poetry run pytest
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Linting
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
poetry run ruff check .
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Formatting
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
poetry run black .
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
MIT License - see LICENSE file for details
|
|
122
|
+
"
|
|
123
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"# Kryten Moderator
|
|
2
|
+
|
|
3
|
+
Kryten moderation service - handles chat moderation and filtering for CyTube.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Real-time chat message monitoring
|
|
8
|
+
- User tracking and management
|
|
9
|
+
- Event-driven architecture using NATS
|
|
10
|
+
- Extensible moderation rules
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
### Prerequisites
|
|
15
|
+
|
|
16
|
+
- Python 3.10 or higher
|
|
17
|
+
- Poetry
|
|
18
|
+
- NATS server running
|
|
19
|
+
- kryten-py library
|
|
20
|
+
|
|
21
|
+
### Setup
|
|
22
|
+
|
|
23
|
+
1. Install dependencies:
|
|
24
|
+
```bash
|
|
25
|
+
poetry install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
2. Copy the example configuration:
|
|
29
|
+
```bash
|
|
30
|
+
cp config.example.json config.json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. Edit `config.json` with your settings:
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"nats_url": "nats://localhost:4222",
|
|
37
|
+
"nats_subject_prefix": "cytube",
|
|
38
|
+
"service_name": "kryten-moderator"
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### Running the Service
|
|
45
|
+
|
|
46
|
+
Using Poetry:
|
|
47
|
+
```bash
|
|
48
|
+
poetry run kryten-moderator --config config.json
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Using the startup script (PowerShell):
|
|
52
|
+
```powershell
|
|
53
|
+
.\start-moderator.ps1
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Using the startup script (Bash):
|
|
57
|
+
```bash
|
|
58
|
+
./start-moderator.sh
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Command Line Options
|
|
62
|
+
|
|
63
|
+
- `--config PATH`: Path to configuration file (default: `/etc/kryten/moderator/config.json`)
|
|
64
|
+
- `--log-level LEVEL`: Set logging level (DEBUG, INFO, WARNING, ERROR)
|
|
65
|
+
|
|
66
|
+
## Event Handling
|
|
67
|
+
|
|
68
|
+
The service currently listens for:
|
|
69
|
+
|
|
70
|
+
- **chatMsg**: Chat messages from users
|
|
71
|
+
- **addUser**: User join events
|
|
72
|
+
|
|
73
|
+
## Development
|
|
74
|
+
|
|
75
|
+
### Running Tests
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
poetry run pytest
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Linting
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
poetry run ruff check .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Formatting
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
poetry run black .
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT License - see LICENSE file for details
|
|
96
|
+
"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Kryten Moderator Service - Chat moderation and filtering."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _read_version() -> str:
|
|
8
|
+
"""Read version from VERSION file."""
|
|
9
|
+
# Try package root first
|
|
10
|
+
version_file = Path(__file__).parent / "VERSION"
|
|
11
|
+
if version_file.exists():
|
|
12
|
+
return version_file.read_text().strip()
|
|
13
|
+
|
|
14
|
+
# Try repository root
|
|
15
|
+
version_file = Path(__file__).parent.parent / "VERSION"
|
|
16
|
+
if version_file.exists():
|
|
17
|
+
return version_file.read_text().strip()
|
|
18
|
+
|
|
19
|
+
return "0.0.0"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__version__ = _read_version()
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Main entry point for kryten-moderator service."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import asyncio
|
|
5
|
+
import logging
|
|
6
|
+
import signal
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from kryten_moderator.service import ModeratorService
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def setup_logging(level: str = "INFO") -> None:
|
|
14
|
+
"""Configure logging for the service."""
|
|
15
|
+
logging.basicConfig(
|
|
16
|
+
level=getattr(logging, level.upper()),
|
|
17
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
18
|
+
handlers=[logging.StreamHandler(sys.stdout)],
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def parse_args() -> argparse.Namespace:
|
|
23
|
+
"""Parse command line arguments."""
|
|
24
|
+
parser = argparse.ArgumentParser(description="Kryten Moderator Service")
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"--config",
|
|
27
|
+
type=Path,
|
|
28
|
+
default=Path("/etc/kryten/moderator/config.json"),
|
|
29
|
+
help="Path to configuration file (default: /etc/kryten/moderator/config.json)",
|
|
30
|
+
)
|
|
31
|
+
parser.add_argument(
|
|
32
|
+
"--log-level",
|
|
33
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
|
34
|
+
default="INFO",
|
|
35
|
+
help="Logging level (default: INFO)",
|
|
36
|
+
)
|
|
37
|
+
return parser.parse_args()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
async def main_async() -> None:
|
|
41
|
+
"""Main async entry point."""
|
|
42
|
+
args = parse_args()
|
|
43
|
+
setup_logging(args.log_level)
|
|
44
|
+
|
|
45
|
+
logger = logging.getLogger(__name__)
|
|
46
|
+
logger.info("Starting Kryten Moderator Service")
|
|
47
|
+
|
|
48
|
+
service = ModeratorService(config_path=args.config)
|
|
49
|
+
|
|
50
|
+
# Setup signal handlers
|
|
51
|
+
loop = asyncio.get_event_loop()
|
|
52
|
+
|
|
53
|
+
def signal_handler(sig: int) -> None:
|
|
54
|
+
logger.info(f"Received signal {sig}, shutting down...")
|
|
55
|
+
asyncio.create_task(service.stop())
|
|
56
|
+
|
|
57
|
+
for sig in (signal.SIGTERM, signal.SIGINT):
|
|
58
|
+
loop.add_signal_handler(sig, lambda s=sig: signal_handler(s))
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
await service.start()
|
|
62
|
+
await service.wait_for_shutdown()
|
|
63
|
+
except KeyboardInterrupt:
|
|
64
|
+
logger.info("Keyboard interrupt received")
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.error(f"Service error: {e}", exc_info=True)
|
|
67
|
+
sys.exit(1)
|
|
68
|
+
finally:
|
|
69
|
+
await service.stop()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def main() -> None:
|
|
73
|
+
"""Main entry point."""
|
|
74
|
+
try:
|
|
75
|
+
asyncio.run(main_async())
|
|
76
|
+
except KeyboardInterrupt:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
main()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Configuration management for kryten-moderator."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Config:
|
|
9
|
+
"""Service configuration."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, config_path: Path):
|
|
12
|
+
"""Initialize configuration from file."""
|
|
13
|
+
self.config_path = config_path
|
|
14
|
+
self._config: dict[str, Any] = {}
|
|
15
|
+
self.load()
|
|
16
|
+
|
|
17
|
+
def load(self) -> None:
|
|
18
|
+
"""Load configuration from file."""
|
|
19
|
+
if not self.config_path.exists():
|
|
20
|
+
raise FileNotFoundError(f"Configuration file not found: {self.config_path}")
|
|
21
|
+
|
|
22
|
+
with open(self.config_path, encoding="utf-8") as f:
|
|
23
|
+
self._config = json.load(f)
|
|
24
|
+
|
|
25
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
26
|
+
"""Get configuration value."""
|
|
27
|
+
return self._config.get(key, default)
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def nats_url(self) -> str:
|
|
31
|
+
"""Get NATS server URL."""
|
|
32
|
+
return self.get("nats_url", "nats://localhost:4222")
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def nats_subject_prefix(self) -> str:
|
|
36
|
+
"""Get NATS subject prefix."""
|
|
37
|
+
return self.get("nats_subject_prefix", "cytube")
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def service_name(self) -> str:
|
|
41
|
+
"""Get service name."""
|
|
42
|
+
return self.get("service_name", "kryten-moderator")
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Main service class for kryten-moderator."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from kryten import KrytenClient
|
|
8
|
+
|
|
9
|
+
from kryten_moderator.config import Config
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ModeratorService:
|
|
15
|
+
"""Kryten Moderator Service."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, config_path: Path):
|
|
18
|
+
"""Initialize the service."""
|
|
19
|
+
self.config = Config(config_path)
|
|
20
|
+
self.client = KrytenClient(
|
|
21
|
+
nats_url=self.config.nats_url,
|
|
22
|
+
subject_prefix=self.config.nats_subject_prefix,
|
|
23
|
+
service_name=self.config.service_name,
|
|
24
|
+
)
|
|
25
|
+
self._shutdown_event = asyncio.Event()
|
|
26
|
+
|
|
27
|
+
async def start(self) -> None:
|
|
28
|
+
"""Start the service."""
|
|
29
|
+
logger.info("Starting moderator service")
|
|
30
|
+
|
|
31
|
+
# Connect to NATS
|
|
32
|
+
await self.client.connect()
|
|
33
|
+
|
|
34
|
+
# Subscribe to events
|
|
35
|
+
await self.client.subscribe("chatMsg", self._handle_chat_message)
|
|
36
|
+
await self.client.subscribe("addUser", self._handle_add_user)
|
|
37
|
+
|
|
38
|
+
logger.info("Moderator service started")
|
|
39
|
+
|
|
40
|
+
async def stop(self) -> None:
|
|
41
|
+
"""Stop the service."""
|
|
42
|
+
logger.info("Stopping moderator service")
|
|
43
|
+
self._shutdown_event.set()
|
|
44
|
+
|
|
45
|
+
# Disconnect from NATS
|
|
46
|
+
await self.client.disconnect()
|
|
47
|
+
|
|
48
|
+
logger.info("Moderator service stopped")
|
|
49
|
+
|
|
50
|
+
async def wait_for_shutdown(self) -> None:
|
|
51
|
+
"""Wait for shutdown signal."""
|
|
52
|
+
await self._shutdown_event.wait()
|
|
53
|
+
|
|
54
|
+
async def _handle_chat_message(self, subject: str, data: dict) -> None:
|
|
55
|
+
"""Handle chatMsg events."""
|
|
56
|
+
username = data.get("username", "unknown")
|
|
57
|
+
msg = data.get("msg", "")
|
|
58
|
+
logger.info(f"Chat message from {username}: {msg}")
|
|
59
|
+
|
|
60
|
+
# TODO: Add moderation logic here
|
|
61
|
+
# - Check for spam
|
|
62
|
+
# - Check for banned words
|
|
63
|
+
# - Check for excessive caps
|
|
64
|
+
# - etc.
|
|
65
|
+
|
|
66
|
+
async def _handle_add_user(self, subject: str, data: dict) -> None:
|
|
67
|
+
"""Handle addUser events."""
|
|
68
|
+
name = data.get("name", "unknown")
|
|
69
|
+
logger.info(f"User added: {name}")
|
|
70
|
+
|
|
71
|
+
# TODO: Add user tracking logic here
|
|
72
|
+
# - Track user joins
|
|
73
|
+
# - Check against ban lists
|
|
74
|
+
# - etc.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "kryten-moderator"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Kryten moderation service - handles chat moderation and filtering"
|
|
5
|
+
authors = ["Kryten Robot Team"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
homepage = "https://github.com/grobertson/kryten-moderator"
|
|
9
|
+
repository = "https://github.com/grobertson/kryten-moderator"
|
|
10
|
+
documentation = "https://github.com/grobertson/kryten-moderator/blob/main/README.md"
|
|
11
|
+
keywords = ["cytube", "moderation", "chat", "nats", "microservices"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Topic :: Communications :: Chat",
|
|
21
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
22
|
+
]
|
|
23
|
+
packages = [{include = "kryten_moderator"}]
|
|
24
|
+
include = ["systemd/*.service", "systemd/README.md", "INSTALL.md"]
|
|
25
|
+
exclude = ["config.json", "config-*.json", "logs/*", "*.log"]
|
|
26
|
+
|
|
27
|
+
[tool.poetry.dependencies]
|
|
28
|
+
python = "^3.10"
|
|
29
|
+
kryten-py = "^0.6.0"
|
|
30
|
+
|
|
31
|
+
[tool.poetry.group.dev.dependencies]
|
|
32
|
+
pytest = "^8.0.0"
|
|
33
|
+
pytest-asyncio = "^0.24.0"
|
|
34
|
+
pytest-mock = "^3.14.0"
|
|
35
|
+
black = "^23.0.0"
|
|
36
|
+
ruff = "^0.1.0"
|
|
37
|
+
mypy = "^1.7.0"
|
|
38
|
+
|
|
39
|
+
[tool.poetry.scripts]
|
|
40
|
+
kryten-moderator = "kryten_moderator.__main__:main"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["poetry-core"]
|
|
44
|
+
build-backend = "poetry.core.masonry.api"
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
|
48
|
+
asyncio_mode = "auto"
|
|
49
|
+
addopts = "-v"
|
|
50
|
+
python_files = ["test_*.py"]
|
|
51
|
+
python_classes = ["Test*"]
|
|
52
|
+
python_functions = ["test_*"]
|
|
53
|
+
|
|
54
|
+
[tool.black]
|
|
55
|
+
line-length = 100
|
|
56
|
+
target-version = ['py310']
|
|
57
|
+
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
line-length = 100
|
|
60
|
+
target-version = "py310"
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint]
|
|
63
|
+
select = ["E", "F", "W", "I", "N"]
|
|
64
|
+
ignore = ["E501"]
|
|
65
|
+
|
|
66
|
+
[tool.ruff.lint.per-file-ignores]
|
|
67
|
+
"__init__.py" = ["E402", "F401"]
|
|
68
|
+
|
|
69
|
+
[tool.mypy]
|
|
70
|
+
python_version = "3.10"
|
|
71
|
+
warn_return_any = true
|
|
72
|
+
warn_unused_configs = true
|
|
73
|
+
disallow_untyped_defs = false
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Systemd Service Files
|
|
2
|
+
|
|
3
|
+
This directory contains systemd service unit files for running kryten-moderator as a system service.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
1. Copy the service file to systemd directory:
|
|
8
|
+
```bash
|
|
9
|
+
sudo cp systemd/kryten-moderator.service /etc/systemd/system/
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. Reload systemd daemon:
|
|
13
|
+
```bash
|
|
14
|
+
sudo systemctl daemon-reload
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
3. Enable the service to start on boot:
|
|
18
|
+
```bash
|
|
19
|
+
sudo systemctl enable kryten-moderator
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
4. Start the service:
|
|
23
|
+
```bash
|
|
24
|
+
sudo systemctl start kryten-moderator
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Service Management
|
|
28
|
+
|
|
29
|
+
Check service status:
|
|
30
|
+
```bash
|
|
31
|
+
sudo systemctl status kryten-moderator
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
View logs:
|
|
35
|
+
```bash
|
|
36
|
+
sudo journalctl -u kryten-moderator -f
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Stop the service:
|
|
40
|
+
```bash
|
|
41
|
+
sudo systemctl stop kryten-moderator
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Restart the service:
|
|
45
|
+
```bash
|
|
46
|
+
sudo systemctl restart kryten-moderator
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
|
|
51
|
+
The service expects:
|
|
52
|
+
- Installation directory: `/opt/kryten-moderator`
|
|
53
|
+
- Configuration file: `/etc/kryten/moderator/config.json`
|
|
54
|
+
- User/Group: `kryten`
|
|
55
|
+
- Log directory: `/var/log/kryten-moderator`
|
|
56
|
+
|
|
57
|
+
Make sure to create these directories and the kryten user before starting the service.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=Kryten Moderator Service
|
|
3
|
+
After=network.target nats.service
|
|
4
|
+
Wants=nats.service
|
|
5
|
+
|
|
6
|
+
[Service]
|
|
7
|
+
Type=simple
|
|
8
|
+
User=kryten
|
|
9
|
+
Group=kryten
|
|
10
|
+
WorkingDirectory=/opt/kryten-moderator
|
|
11
|
+
Environment="PATH=/opt/kryten-moderator/.venv/bin:/usr/local/bin:/usr/bin:/bin"
|
|
12
|
+
ExecStart=/opt/kryten-moderator/.venv/bin/kryten-moderator --config /etc/kryten/moderator/config.json
|
|
13
|
+
Restart=on-failure
|
|
14
|
+
RestartSec=5
|
|
15
|
+
StandardOutput=journal
|
|
16
|
+
StandardError=journal
|
|
17
|
+
SyslogIdentifier=kryten-moderator
|
|
18
|
+
|
|
19
|
+
# Security hardening
|
|
20
|
+
NoNewPrivileges=true
|
|
21
|
+
PrivateTmp=true
|
|
22
|
+
ProtectSystem=strict
|
|
23
|
+
ProtectHome=true
|
|
24
|
+
ReadWritePaths=/var/log/kryten-moderator
|
|
25
|
+
ReadOnlyPaths=/etc/kryten/moderator
|
|
26
|
+
|
|
27
|
+
[Install]
|
|
28
|
+
WantedBy=multi-user.target
|