Concurrency & correctness: - #10: guard IpDb Query/IsLoaded with RLock so Reload() (which reassigns d.r and closes the old reader) cannot race with concurrent lookups. Confirmed via -race regression test. - #12: replace DbUpdatedAt time.Time with atomic.Int64 (cron writes, /metrics reads) to fix the read/write data race. - #11: graceful HTTP shutdown (srv.Shutdown with 10s timeout) instead of srv.Close() aborting in-flight requests. - #14: stop swallowing mergeMmdb() errors in fetchDbs() — keep the previous DB when a merge fails instead of reloading a possibly-empty output. - #13: add resty timeout (2m) + retry (x2) to download() so a hung CDN can't stall the daily cron forever. - #15: correct HTTP status codes (503 db loading, 404 not found via new ErrNotFound sentinel, 500 otherwise) instead of 200 on query error. Robustness: - #16: surface osx.Copy dstFile.Close() errors (flush may fail) via named return + defer. Dependency migration: - #17: migrate maxminddb-golang v1 -> v2. v2 is a breaking API (LookupNetwork -> Lookup returning Result, netip.Addr), so Query was rewritten; v1 dropped from go.mod. Tests: - #21: add internal/data unit tests (valid/invalid/not-found lookup) plus a concurrent Query/Reload race regression test. chdir to repo root in TestMain because data helpers use relative paths. Cleanup: - #18: README Go version 1.22 -> 1.25. - #19: replace stray fmt.Printf with zerolog in ipdb.go. - #20: .env.example API_PORT 28080 -> 8080 (container port, matches docker-compose 28080:8080 mapping) with an explanatory comment. Closes #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21 Co-Authored-By: Claude <noreply@anthropic.com>
266 lines
5.2 KiB
Markdown
266 lines
5.2 KiB
Markdown
# IP Info Service
|
|
|
|
A high-performance IP geolocation service built with Go that provides detailed information about IP addresses including country, ASN (Autonomous System Number), and other geolocation data.
|
|
|
|
## Features
|
|
|
|
- 🌍 IP geolocation lookup with country information
|
|
- 🏢 ASN (Autonomous System Number) information
|
|
- 🚀 High-performance HTTP API
|
|
- 🔄 Automatic database updates
|
|
- 🐳 Docker support
|
|
- 📊 Metrics endpoint for monitoring
|
|
- 🛡️ Input validation and error handling
|
|
|
|
## Quick Start
|
|
|
|
### Using Docker (Recommended)
|
|
|
|
1. Clone the repository:
|
|
```bash
|
|
git clone <repository-url>
|
|
cd ip-info
|
|
```
|
|
|
|
2. Start the service using Docker Compose:
|
|
```bash
|
|
docker-compose up -d
|
|
```
|
|
|
|
The service will be available at `http://localhost:28080`
|
|
|
|
### Manual Installation
|
|
|
|
1. Install Go 1.25 or later
|
|
2. Clone and build:
|
|
```bash
|
|
git clone <repository-url>
|
|
cd ip-info
|
|
go mod download
|
|
go build -o ip-info
|
|
./ip-info
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### 1. Get Your IP Information
|
|
|
|
**Plain Text Response:**
|
|
```bash
|
|
curl http://localhost:28080/
|
|
# Returns: 192.168.1.100
|
|
```
|
|
|
|
**JSON Response:**
|
|
```bash
|
|
curl http://localhost:28080/json
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"ip": "192.168.1.100",
|
|
"country": "US",
|
|
"country_name": "United States",
|
|
"asn": "AS15169",
|
|
"asn_org": "Google LLC"
|
|
}
|
|
```
|
|
|
|
### 2. Look Up Specific IP Address
|
|
|
|
**Query any IP address:**
|
|
```bash
|
|
curl http://localhost:28080/8.8.8.8
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"ip": "8.8.8.8",
|
|
"country": "US",
|
|
"country_name": "United States",
|
|
"asn": "AS15169",
|
|
"asn_org": "Google LLC"
|
|
}
|
|
```
|
|
|
|
### 3. Metrics Endpoint
|
|
|
|
Monitor service health and performance:
|
|
```bash
|
|
curl http://localhost:28080/metrics
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `API_PORT` | `8080` | Port for the HTTP server |
|
|
| `GIN_TRUSTED_PROXY_IP` | - | Trusted proxy IP for client IP detection |
|
|
| `GIN_MODE` | `debug` | Gin framework mode (`debug`, `release`) |
|
|
|
|
### Using .env File
|
|
|
|
Create a `.env` file in the project root:
|
|
```env
|
|
API_PORT=8080
|
|
GIN_TRUSTED_PROXY_IP=127.0.0.1
|
|
GIN_MODE=release
|
|
```
|
|
|
|
## Docker Configuration
|
|
|
|
### Docker Compose
|
|
|
|
The included `docker-compose.yml` provides:
|
|
- Service on port 28080 (maps to container port 8080)
|
|
- Persistent cache volume
|
|
- Auto-restart policy
|
|
- Vietnam timezone configuration
|
|
|
|
### Custom Docker Build
|
|
|
|
```bash
|
|
# Build image
|
|
docker build -t ip-info .
|
|
|
|
# Run container
|
|
docker run -p 8080:8080 -v $(pwd)/.cache:/app/.cache ip-info
|
|
```
|
|
|
|
## Data Sources
|
|
|
|
The service automatically downloads and updates IP geolocation databases from:
|
|
- **Country Data**: GeoLite2 Country database via jsDelivr CDN
|
|
- **ASN Data**: GeoLite2 ASN database via jsDelivr CDN
|
|
|
|
Database updates happen automatically in the background to ensure data freshness.
|
|
|
|
## Usage Examples
|
|
|
|
### Basic IP Lookup
|
|
```bash
|
|
# Get information about Google's DNS
|
|
curl http://localhost:28080/8.8.8.8
|
|
|
|
# Get information about Cloudflare's DNS
|
|
curl http://localhost:28080/1.1.1.1
|
|
|
|
# Get your own IP info
|
|
curl http://localhost:28080/json
|
|
```
|
|
|
|
### Integration Examples
|
|
|
|
**JavaScript/Node.js:**
|
|
```javascript
|
|
const response = await fetch('http://localhost:28080/8.8.8.8');
|
|
const ipInfo = await response.json();
|
|
console.log(ipInfo);
|
|
```
|
|
|
|
**Python:**
|
|
```python
|
|
import requests
|
|
|
|
response = requests.get('http://localhost:28080/8.8.8.8')
|
|
ip_info = response.json()
|
|
print(ip_info)
|
|
```
|
|
|
|
**cURL with jq:**
|
|
```bash
|
|
curl -s http://localhost:28080/8.8.8.8 | jq .
|
|
```
|
|
|
|
## Response Format
|
|
|
|
All JSON responses include:
|
|
- `ip`: The queried IP address
|
|
- `country`: ISO 3166-1 alpha-2 country code
|
|
- `country_name`: Full country name
|
|
- `asn`: Autonomous System Number (when available)
|
|
- `asn_org`: ASN organization name (when available)
|
|
|
|
## Error Handling
|
|
|
|
### Invalid IP Address
|
|
```bash
|
|
curl http://localhost:28080/invalid-ip
|
|
```
|
|
Response:
|
|
```json
|
|
{
|
|
"error": "invalid ip"
|
|
}
|
|
```
|
|
|
|
### Service Unavailable
|
|
If the database is not loaded yet:
|
|
```
|
|
HTTP 500: Try again later
|
|
```
|
|
|
|
## Performance
|
|
|
|
- **Startup Time**: Database loads automatically on startup
|
|
- **Response Time**: Sub-millisecond IP lookups after database load
|
|
- **Memory Usage**: Optimized MMDB format for efficient memory usage
|
|
- **Concurrency**: Built with Go's excellent concurrency support
|
|
|
|
## Monitoring
|
|
|
|
### Health Check
|
|
```bash
|
|
curl http://localhost:28080/metrics
|
|
```
|
|
|
|
### Logs
|
|
The service provides structured JSON logging with different log levels. In Docker:
|
|
```bash
|
|
docker-compose logs -f ip-info
|
|
```
|
|
|
|
## Development
|
|
|
|
### Local Development
|
|
```bash
|
|
# Install dependencies
|
|
go mod download
|
|
|
|
# Run in development mode
|
|
go run main.go
|
|
|
|
# Build for production
|
|
go build -o ip-info
|
|
```
|
|
|
|
### Project Structure
|
|
```
|
|
├── main.go # Application entry point
|
|
├── configs/ # Configuration files
|
|
├── internal/
|
|
│ ├── data/ # Database handling
|
|
│ └── services/
|
|
│ ├── api/ # HTTP API handlers
|
|
│ └── db_updater/ # Database update service
|
|
├── pkg/ # Shared packages
|
|
├── data/ # Database files (auto-generated)
|
|
└── docker-compose.yml # Docker configuration
|
|
```
|
|
|
|
## License
|
|
|
|
[Add your license information here]
|
|
|
|
## Contributing
|
|
|
|
[Add contribution guidelines here]
|
|
|
|
## Support
|
|
|
|
For issues and questions, please [open an issue](link-to-issues) or contact the maintainers.
|