golinks 1.0.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.
- golinks-1.0.0/.gitignore +52 -0
- golinks-1.0.0/.python-version +1 -0
- golinks-1.0.0/CLAUDE.md +82 -0
- golinks-1.0.0/LICENSE +21 -0
- golinks-1.0.0/PKG-INFO +55 -0
- golinks-1.0.0/README.md +30 -0
- golinks-1.0.0/config.json +7 -0
- golinks-1.0.0/install.sh +295 -0
- golinks-1.0.0/pyproject.toml +52 -0
- golinks-1.0.0/src/__init__.py +0 -0
- golinks-1.0.0/src/models.py +14 -0
- golinks-1.0.0/src/server.py +234 -0
- golinks-1.0.0/src/templates/base.html +26 -0
- golinks-1.0.0/src/templates/error.html +58 -0
- golinks-1.0.0/src/templates/links.html +60 -0
- golinks-1.0.0/uninstall.sh +197 -0
- golinks-1.0.0/uv.lock +222 -0
golinks-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
eggs/
|
|
11
|
+
.eggs/
|
|
12
|
+
*.manifest
|
|
13
|
+
*.spec
|
|
14
|
+
|
|
15
|
+
# Virtual environments
|
|
16
|
+
venv/
|
|
17
|
+
ENV/
|
|
18
|
+
env/
|
|
19
|
+
.venv
|
|
20
|
+
|
|
21
|
+
# IDEs
|
|
22
|
+
.vscode/
|
|
23
|
+
.idea/
|
|
24
|
+
*.swp
|
|
25
|
+
*.swo
|
|
26
|
+
*~
|
|
27
|
+
.DS_Store
|
|
28
|
+
|
|
29
|
+
# Testing
|
|
30
|
+
.pytest_cache/
|
|
31
|
+
.coverage
|
|
32
|
+
htmlcov/
|
|
33
|
+
.tox/
|
|
34
|
+
.mypy_cache/
|
|
35
|
+
.ruff_cache/
|
|
36
|
+
|
|
37
|
+
# Package managers
|
|
38
|
+
pip-log.txt
|
|
39
|
+
pip-delete-this-directory.txt
|
|
40
|
+
|
|
41
|
+
# Distribution / packaging
|
|
42
|
+
.Python
|
|
43
|
+
develop-eggs/
|
|
44
|
+
downloads/
|
|
45
|
+
lib/
|
|
46
|
+
lib64/
|
|
47
|
+
parts/
|
|
48
|
+
sdist/
|
|
49
|
+
var/
|
|
50
|
+
wheels/
|
|
51
|
+
*.whl
|
|
52
|
+
.env
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
golinks-1.0.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Development Commands
|
|
6
|
+
|
|
7
|
+
Use uv to run Python code:
|
|
8
|
+
```bash
|
|
9
|
+
# Run the server
|
|
10
|
+
uv run golinks
|
|
11
|
+
|
|
12
|
+
# Run with custom config
|
|
13
|
+
uv run golinks --config /path/to/config.json
|
|
14
|
+
|
|
15
|
+
# Run with custom port
|
|
16
|
+
uv run golinks --port 9000
|
|
17
|
+
|
|
18
|
+
# Run any Python command
|
|
19
|
+
uv run python <script.py>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Linting
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Run linter
|
|
26
|
+
uv run ruff check .
|
|
27
|
+
|
|
28
|
+
# Fix linting issues
|
|
29
|
+
uv run ruff check --fix .
|
|
30
|
+
|
|
31
|
+
# Format code
|
|
32
|
+
uv run ruff format .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Architecture
|
|
36
|
+
|
|
37
|
+
### Core Components
|
|
38
|
+
|
|
39
|
+
**HTTP Server** (`src/server.py`):
|
|
40
|
+
- Uses Python's built-in `http.server` module with custom `GoLinksHandler`
|
|
41
|
+
- Handles redirects based on path matching against configured shortcuts
|
|
42
|
+
- Hot-reloads configuration on each request (no restart needed)
|
|
43
|
+
- Serves web interface at root path showing all available links
|
|
44
|
+
|
|
45
|
+
**Configuration** (`src/models.py`):
|
|
46
|
+
- Pydantic models for type-safe configuration handling
|
|
47
|
+
- Supports simple string URLs or template objects with Jinja2 templating
|
|
48
|
+
- `LinkTemplate` allows for parameterized URLs with defaults
|
|
49
|
+
|
|
50
|
+
**Templates** (`src/templates/`):
|
|
51
|
+
- Jinja2 templates for the web interface
|
|
52
|
+
- `base.html`: Base template with common styles
|
|
53
|
+
- `links.html`: Shows all configured shortcuts
|
|
54
|
+
- `error.html`: Friendly 404 page for unknown shortcuts
|
|
55
|
+
|
|
56
|
+
### Key Design Patterns
|
|
57
|
+
|
|
58
|
+
1. **Hot-reload Configuration**: Config is loaded fresh on each request from JSON file
|
|
59
|
+
2. **Template URLs**: Links can use Jinja2 templates with query parameters as variables
|
|
60
|
+
3. **Query Parameter Preservation**: Unmatched query params are passed through to destination
|
|
61
|
+
4. **No External Dependencies**: Uses Python stdlib where possible (except Jinja2, Pydantic)
|
|
62
|
+
|
|
63
|
+
### Configuration Format
|
|
64
|
+
|
|
65
|
+
Simple redirects:
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"github": "https://github.com"
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Template redirects with defaults:
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"search": {
|
|
76
|
+
"template_url": "https://www.google.com/search?q={{q|default('python')}}",
|
|
77
|
+
"defaults": {
|
|
78
|
+
"q": "python"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
golinks-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Your Name
|
|
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.
|
golinks-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: golinks
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A local go links redirect service for URL shortcuts
|
|
5
|
+
Project-URL: Homepage, https://github.com/yourusername/golinks
|
|
6
|
+
Project-URL: Repository, https://github.com/yourusername/golinks.git
|
|
7
|
+
Project-URL: Issues, https://github.com/yourusername/golinks/issues
|
|
8
|
+
Author-email: Haran Rajkumar <haranrajkumar97@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: golinks,redirect,shortcuts,url-shortener
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
20
|
+
Classifier: Topic :: Utilities
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: jinja2>=3.1.6
|
|
23
|
+
Requires-Dist: pydantic>=2.11.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Golinks
|
|
27
|
+
|
|
28
|
+
A simple local HTTP redirect service that turns short URLs like `go/github` into full URLs.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
### Install manually
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Clone the repository
|
|
36
|
+
git clone https://github.com/yourusername/golinks.git
|
|
37
|
+
cd golinks
|
|
38
|
+
|
|
39
|
+
# Run the install script
|
|
40
|
+
./install
|
|
41
|
+
|
|
42
|
+
# Edit the config
|
|
43
|
+
vim ~/.config/golinks/config.json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
The `./install` script automates the entire setup:
|
|
49
|
+
1. Installs the Python package using uv
|
|
50
|
+
2. Adds `127.0.0.1 go` to your `/etc/hosts` file (with sudo permission)
|
|
51
|
+
3. Sets up port forwarding from port 80 to 8888 using pfctl (macOS) or iptables (Linux), so you can use `go/shortcut` instead of `go:8888/shortcut`
|
|
52
|
+
4. Sets up a LaunchAgent (macOS) or systemd service (Linux) to run the server at startup
|
|
53
|
+
5. Starts the golinks server immediately on port 8888
|
|
54
|
+
|
|
55
|
+
Once installed, golinks runs a lightweight HTTP server that reads shortcuts from a JSON config file at `~/.golinks/config.json` and redirects `http://go/shortcut` to the configured destination URL. The config file is hot-reloaded, so you can add new shortcuts without restarting the server.
|
golinks-1.0.0/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Golinks
|
|
2
|
+
|
|
3
|
+
A simple local HTTP redirect service that turns short URLs like `go/github` into full URLs.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Install manually
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Clone the repository
|
|
11
|
+
git clone https://github.com/yourusername/golinks.git
|
|
12
|
+
cd golinks
|
|
13
|
+
|
|
14
|
+
# Run the install script
|
|
15
|
+
./install
|
|
16
|
+
|
|
17
|
+
# Edit the config
|
|
18
|
+
vim ~/.config/golinks/config.json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## How it works
|
|
22
|
+
|
|
23
|
+
The `./install` script automates the entire setup:
|
|
24
|
+
1. Installs the Python package using uv
|
|
25
|
+
2. Adds `127.0.0.1 go` to your `/etc/hosts` file (with sudo permission)
|
|
26
|
+
3. Sets up port forwarding from port 80 to 8888 using pfctl (macOS) or iptables (Linux), so you can use `go/shortcut` instead of `go:8888/shortcut`
|
|
27
|
+
4. Sets up a LaunchAgent (macOS) or systemd service (Linux) to run the server at startup
|
|
28
|
+
5. Starts the golinks server immediately on port 8888
|
|
29
|
+
|
|
30
|
+
Once installed, golinks runs a lightweight HTTP server that reads shortcuts from a JSON config file at `~/.golinks/config.json` and redirects `http://go/shortcut` to the configured destination URL. The config file is hot-reloaded, so you can add new shortcuts without restarting the server.
|
golinks-1.0.0/install.sh
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
RED='\033[0;31m'
|
|
6
|
+
GREEN='\033[0;32m'
|
|
7
|
+
YELLOW='\033[1;33m'
|
|
8
|
+
BLUE='\033[0;34m'
|
|
9
|
+
NC='\033[0m' # No Color
|
|
10
|
+
|
|
11
|
+
echo_info() {
|
|
12
|
+
echo -e "${BLUE}[INFO]${NC} $1"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
echo_success() {
|
|
16
|
+
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
echo_warning() {
|
|
20
|
+
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
echo_error() {
|
|
24
|
+
echo -e "${RED}[ERROR]${NC} $1"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Check if already installed
|
|
28
|
+
check_installation() {
|
|
29
|
+
if command -v golinks &> /dev/null; then
|
|
30
|
+
if uv tool list 2>/dev/null | grep -q golinks; then
|
|
31
|
+
echo_warning "golinks is already installed"
|
|
32
|
+
return 0
|
|
33
|
+
fi
|
|
34
|
+
fi
|
|
35
|
+
return 1
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Install uv if missing
|
|
39
|
+
install_uv() {
|
|
40
|
+
if ! command -v uv &> /dev/null; then
|
|
41
|
+
echo_info "Installing uv package manager..."
|
|
42
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
43
|
+
|
|
44
|
+
# Source shell config to get uv in PATH
|
|
45
|
+
if [ -f "$HOME/.bashrc" ]; then
|
|
46
|
+
source "$HOME/.bashrc"
|
|
47
|
+
elif [ -f "$HOME/.zshrc" ]; then
|
|
48
|
+
source "$HOME/.zshrc"
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Add to current shell session
|
|
52
|
+
export PATH="$HOME/.cargo/bin:$PATH"
|
|
53
|
+
|
|
54
|
+
if ! command -v uv &> /dev/null; then
|
|
55
|
+
echo_error "Failed to install uv. Please install manually."
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
echo_success "uv installed successfully"
|
|
59
|
+
else
|
|
60
|
+
echo_info "uv is already installed"
|
|
61
|
+
fi
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Install golinks tool
|
|
65
|
+
install_golinks() {
|
|
66
|
+
echo_info "Installing golinks..."
|
|
67
|
+
|
|
68
|
+
# Install from the current directory if we're in the repo
|
|
69
|
+
if [ -f "pyproject.toml" ]; then
|
|
70
|
+
uv tool install .
|
|
71
|
+
else
|
|
72
|
+
# Install from PyPI or git
|
|
73
|
+
uv tool install golinks
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
if [ $? -eq 0 ]; then
|
|
77
|
+
echo_success "golinks installed successfully"
|
|
78
|
+
else
|
|
79
|
+
echo_error "Failed to install golinks"
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Create configuration directory and file
|
|
85
|
+
setup_config() {
|
|
86
|
+
CONFIG_DIR="$HOME/.config/golinks"
|
|
87
|
+
CONFIG_FILE="$CONFIG_DIR/config.json"
|
|
88
|
+
|
|
89
|
+
echo_info "Setting up configuration..."
|
|
90
|
+
|
|
91
|
+
# Create config directory
|
|
92
|
+
mkdir -p "$CONFIG_DIR"
|
|
93
|
+
|
|
94
|
+
# Create config file if it doesn't exist
|
|
95
|
+
if [ ! -f "$CONFIG_FILE" ]; then
|
|
96
|
+
cat > "$CONFIG_FILE" <<EOF
|
|
97
|
+
{
|
|
98
|
+
"github": "https://github.com",
|
|
99
|
+
"mail": "https://gmail.com",
|
|
100
|
+
"calendar": "https://calendar.google.com",
|
|
101
|
+
"prs": {
|
|
102
|
+
"template_url": "https://github.com/MithraAI/{1}/pull/{2}",
|
|
103
|
+
"defaults": {
|
|
104
|
+
"1": "istari"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"issue": {
|
|
108
|
+
"template_url": "https://github.com/{1}/{2}/issues/{3}",
|
|
109
|
+
"defaults": {
|
|
110
|
+
"1": "anthropics",
|
|
111
|
+
"2": "claude-code"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
EOF
|
|
116
|
+
echo_success "Configuration file created at $CONFIG_FILE"
|
|
117
|
+
else
|
|
118
|
+
echo_info "Configuration file already exists"
|
|
119
|
+
fi
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Add entry to /etc/hosts
|
|
123
|
+
setup_hosts() {
|
|
124
|
+
echo_info "Configuring /etc/hosts..."
|
|
125
|
+
|
|
126
|
+
# Check if entry already exists
|
|
127
|
+
if grep -q "127.0.0.1[[:space:]]*go$" /etc/hosts 2>/dev/null; then
|
|
128
|
+
echo_info "/etc/hosts already configured"
|
|
129
|
+
else
|
|
130
|
+
echo_info "Adding 'go' to /etc/hosts (requires sudo)..."
|
|
131
|
+
echo "127.0.0.1 go" | sudo tee -a /etc/hosts > /dev/null
|
|
132
|
+
echo_success "Added 'go' to /etc/hosts"
|
|
133
|
+
fi
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Setup LaunchAgent
|
|
137
|
+
setup_launchagent() {
|
|
138
|
+
PLIST_DIR="$HOME/Library/LaunchAgents"
|
|
139
|
+
PLIST_FILE="$PLIST_DIR/com.user.golinks.plist"
|
|
140
|
+
|
|
141
|
+
echo_info "Setting up LaunchAgent..."
|
|
142
|
+
|
|
143
|
+
# Create LaunchAgents directory if it doesn't exist
|
|
144
|
+
mkdir -p "$PLIST_DIR"
|
|
145
|
+
|
|
146
|
+
# Find golinks executable path
|
|
147
|
+
GOLINKS_PATH=$(which golinks)
|
|
148
|
+
if [ -z "$GOLINKS_PATH" ]; then
|
|
149
|
+
echo_error "golinks command not found in PATH"
|
|
150
|
+
exit 1
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
# Create plist file
|
|
154
|
+
cat > "$PLIST_FILE" <<EOF
|
|
155
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
156
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
157
|
+
<plist version="1.0">
|
|
158
|
+
<dict>
|
|
159
|
+
<key>Label</key>
|
|
160
|
+
<string>com.user.golinks</string>
|
|
161
|
+
<key>ProgramArguments</key>
|
|
162
|
+
<array>
|
|
163
|
+
<string>$GOLINKS_PATH</string>
|
|
164
|
+
<string>--port</string>
|
|
165
|
+
<string>8080</string>
|
|
166
|
+
<string>--config</string>
|
|
167
|
+
<string>$HOME/.config/golinks/config.json</string>
|
|
168
|
+
</array>
|
|
169
|
+
<key>KeepAlive</key>
|
|
170
|
+
<true/>
|
|
171
|
+
<key>RunAtLoad</key>
|
|
172
|
+
<true/>
|
|
173
|
+
<key>StandardOutPath</key>
|
|
174
|
+
<string>$HOME/.config/golinks/stdout.log</string>
|
|
175
|
+
<key>StandardErrorPath</key>
|
|
176
|
+
<string>$HOME/.config/golinks/stderr.log</string>
|
|
177
|
+
</dict>
|
|
178
|
+
</plist>
|
|
179
|
+
EOF
|
|
180
|
+
|
|
181
|
+
echo_success "LaunchAgent plist created"
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
# Setup port forwarding (port 80 -> 8080)
|
|
185
|
+
setup_port_forwarding() {
|
|
186
|
+
echo_info "Setting up port 80 forwarding to 8080..."
|
|
187
|
+
|
|
188
|
+
# Check if pf anchor file already exists
|
|
189
|
+
if [ -f "/etc/pf.anchors/golinks" ]; then
|
|
190
|
+
echo_warning "Port forwarding anchor already exists"
|
|
191
|
+
else
|
|
192
|
+
echo_info "Creating port forwarding rule (requires sudo)..."
|
|
193
|
+
|
|
194
|
+
# Create the anchor file
|
|
195
|
+
echo "rdr pass on lo0 inet proto tcp from any to 127.0.0.1 port 80 -> 127.0.0.1 port 8080" | sudo tee /etc/pf.anchors/golinks > /dev/null
|
|
196
|
+
|
|
197
|
+
echo_success "Port forwarding anchor created"
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
# Check if pf.conf already includes our anchor
|
|
201
|
+
if sudo grep -q "golinks" /etc/pf.conf 2>/dev/null; then
|
|
202
|
+
echo_info "pf.conf already configured for golinks"
|
|
203
|
+
else
|
|
204
|
+
echo_info "Updating pf.conf (requires sudo)..."
|
|
205
|
+
|
|
206
|
+
# Backup pf.conf
|
|
207
|
+
sudo cp /etc/pf.conf /etc/pf.conf.backup.$(date +%Y%m%d%H%M%S)
|
|
208
|
+
|
|
209
|
+
# Add rdr-anchor after other rdr-anchor lines (with proper newline)
|
|
210
|
+
sudo sed -i '' '/^rdr-anchor "com.apple\/\*"/a\
|
|
211
|
+
rdr-anchor "golinks"
|
|
212
|
+
' /etc/pf.conf
|
|
213
|
+
|
|
214
|
+
# Add load anchor after the com.apple load anchor (with proper newline)
|
|
215
|
+
sudo sed -i '' '/^load anchor "com.apple" from "\/etc\/pf.anchors\/com.apple"/a\
|
|
216
|
+
load anchor "golinks" from "/etc/pf.anchors/golinks"
|
|
217
|
+
' /etc/pf.conf
|
|
218
|
+
|
|
219
|
+
echo_success "pf.conf updated"
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
# Enable pfctl
|
|
223
|
+
echo_info "Enabling packet filtering..."
|
|
224
|
+
sudo pfctl -e 2>/dev/null || true
|
|
225
|
+
sudo pfctl -f /etc/pf.conf 2>/dev/null || {
|
|
226
|
+
echo_warning "Could not reload pf.conf. You may need to restart or manually run: sudo pfctl -f /etc/pf.conf"
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
echo_success "Port forwarding setup complete (80 -> 8080)"
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
# Start the service
|
|
233
|
+
start_service() {
|
|
234
|
+
PLIST_FILE="$HOME/Library/LaunchAgents/com.user.golinks.plist"
|
|
235
|
+
|
|
236
|
+
echo_info "Starting golinks service..."
|
|
237
|
+
|
|
238
|
+
# Unload if already loaded
|
|
239
|
+
launchctl unload "$PLIST_FILE" 2>/dev/null || true
|
|
240
|
+
|
|
241
|
+
# Load the service
|
|
242
|
+
launchctl load "$PLIST_FILE"
|
|
243
|
+
|
|
244
|
+
# Wait for service to start
|
|
245
|
+
echo_info "Waiting for service to start..."
|
|
246
|
+
sleep 3
|
|
247
|
+
|
|
248
|
+
# Verify service is running
|
|
249
|
+
if curl -s http://localhost:8080/ | grep -q "Go Links" 2>/dev/null; then
|
|
250
|
+
echo_success "Service started successfully at http://localhost:8080"
|
|
251
|
+
else
|
|
252
|
+
echo_warning "Service may not be running. Check logs at ~/.config/golinks/"
|
|
253
|
+
fi
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
# Main installation flow
|
|
257
|
+
main() {
|
|
258
|
+
echo -e "${GREEN}╔══════════════════════════════════════╗${NC}"
|
|
259
|
+
echo -e "${GREEN}║ GoLinks Installation Script ║${NC}"
|
|
260
|
+
echo -e "${GREEN}╚══════════════════════════════════════╝${NC}"
|
|
261
|
+
echo ""
|
|
262
|
+
|
|
263
|
+
# Check if already installed
|
|
264
|
+
if check_installation; then
|
|
265
|
+
read -p "golinks is already installed. Reinstall? (y/N): " -n 1 -r
|
|
266
|
+
echo
|
|
267
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
268
|
+
echo_info "Installation cancelled"
|
|
269
|
+
exit 0
|
|
270
|
+
fi
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
# Run installation steps
|
|
274
|
+
install_uv
|
|
275
|
+
install_golinks
|
|
276
|
+
setup_config
|
|
277
|
+
setup_hosts
|
|
278
|
+
setup_launchagent
|
|
279
|
+
setup_port_forwarding
|
|
280
|
+
start_service
|
|
281
|
+
|
|
282
|
+
echo ""
|
|
283
|
+
echo -e "${GREEN}╔══════════════════════════════════════╗${NC}"
|
|
284
|
+
echo -e "${GREEN}║ Installation Complete! 🎉 ║${NC}"
|
|
285
|
+
echo -e "${GREEN}╚══════════════════════════════════════╝${NC}"
|
|
286
|
+
echo ""
|
|
287
|
+
echo "Usage examples:"
|
|
288
|
+
echo " • Visit http://go to see the configured links"
|
|
289
|
+
echo " • Use a link: open http://go/<slug>"
|
|
290
|
+
echo ""
|
|
291
|
+
echo "Logs are available at: ~/.config/golinks/"
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
# Run main function
|
|
295
|
+
main
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[tool.hatch.build.targets.wheel]
|
|
6
|
+
packages = ["src"]
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
name = "golinks"
|
|
10
|
+
version = "1.0.0"
|
|
11
|
+
description = "A local go links redirect service for URL shortcuts"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.11"
|
|
14
|
+
license = { text = "MIT" } # Add your preferred license
|
|
15
|
+
authors = [
|
|
16
|
+
{ name = "Haran Rajkumar", email = "haranrajkumar97@gmail.com" },
|
|
17
|
+
]
|
|
18
|
+
keywords = ["golinks", "url-shortener", "redirect", "shortcuts"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
28
|
+
"Topic :: Utilities",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"jinja2>=3.1.6",
|
|
32
|
+
"pydantic>=2.11.9",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/yourusername/golinks"
|
|
37
|
+
Repository = "https://github.com/yourusername/golinks.git"
|
|
38
|
+
Issues = "https://github.com/yourusername/golinks/issues"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
golinks = "src.server:main"
|
|
42
|
+
|
|
43
|
+
[dependency-groups]
|
|
44
|
+
dev = [
|
|
45
|
+
"ruff>=0.13.0",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
[tool.pyright]
|
|
51
|
+
reportUnusedCallResult = false
|
|
52
|
+
typeCheckingMode = "standard"
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field, RootModel
|
|
2
|
+
from typing import Union, Dict
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class LinkTemplate(BaseModel):
|
|
6
|
+
template_url: str
|
|
7
|
+
defaults: Dict[str, str] = Field(default_factory=dict)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
LinkConfig = Union[str, LinkTemplate]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class GoLinksConfig(RootModel):
|
|
14
|
+
root: Dict[str, LinkConfig]
|