diff --git a/.gitea/workflows/docker-build.yml b/.gitea/workflows/docker-build.yml index 822fe1b..c2b0fbc 100644 --- a/.gitea/workflows/docker-build.yml +++ b/.gitea/workflows/docker-build.yml @@ -48,7 +48,7 @@ jobs: docker push ${{ env.IMAGE_PATH }}:${{ matrix.arch }}-latest amend-manifest: - runs-on: ubuntu-latest + runs-on: linux needs: [build] steps: - name: Login to Docker Registry diff --git a/README.md b/README.md new file mode 100644 index 0000000..39cc4eb --- /dev/null +++ b/README.md @@ -0,0 +1,265 @@ +# 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 +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.22 or later +2. Clone and build: +```bash +git clone +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. diff --git a/internal/services/api/handler_ip.go b/internal/services/api/handler_ip.go index 981a971..2cb5f93 100644 --- a/internal/services/api/handler_ip.go +++ b/internal/services/api/handler_ip.go @@ -5,6 +5,6 @@ import ( "net/http" ) -func HandleIp(c *gin.Context) { +func HandleMyIp(c *gin.Context) { c.String(http.StatusOK, c.ClientIP()) } diff --git a/internal/services/api/handler_json.go b/internal/services/api/handler_json.go index 8d976eb..39a4c00 100644 --- a/internal/services/api/handler_json.go +++ b/internal/services/api/handler_json.go @@ -3,12 +3,26 @@ package api import ( "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" + "net" "net/http" "thuanle.me/ip-info/internal/data" ) func HandleJson(c *gin.Context) { ip := c.ClientIP() + HandleIpInfo(c, ip) +} + +func HandleOtherIp(c *gin.Context) { + ip := c.Param("ip") + if net.ParseIP(ip) == nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ip"}) + return + } + HandleIpInfo(c, ip) +} + +func HandleIpInfo(c *gin.Context, ip string) { if !data.Ins().IsLoaded() { log.Error().Msg("DB is not loaded") c.String(http.StatusInternalServerError, "Try again later") @@ -26,5 +40,4 @@ func HandleJson(c *gin.Context) { ipData["ip"] = ip c.JSON(http.StatusOK, ipData) - } diff --git a/internal/services/api/main.go b/internal/services/api/main.go index 943ffd0..4bc2ee5 100644 --- a/internal/services/api/main.go +++ b/internal/services/api/main.go @@ -22,9 +22,10 @@ func StartApiService() { _ = engine.SetTrustedProxies([]string{trustedProxyIP}) } - engine.GET("/", HandleIp) + engine.GET("/", HandleMyIp) engine.GET("/json", HandleJson) engine.GET("/metrics", HandleMetrics) + engine.GET("/:ip", HandleOtherIp) port := os.Getenv(key.EnvApiPort) if len(port) == 0 {