Repository: soorajb/loc2country
Branch: master
Commit: 0e5b32e132fb
Files: 10
Total size: 7.6 KB
Directory structure:
gitextract_vsbryt61/
├── .gitignore
├── README.md
├── bin/
│ ├── .keep
│ ├── server_amd64
│ └── server_darwin
├── build_linux.sh
├── data/
│ └── .keep
├── src/
│ ├── server.go
│ └── server_test.go
└── start.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea/
dump.rdb
================================================
FILE: README.md
================================================
## Loc2Country
Location coordinates (lat/lon) to ISO alpha-3 country code. Responds in microseconds.
## Manual
Input format: latitude, longitude
Output format: 3-letter-ISO-country-code, time-taken-to-respond-in-nanos
## HowTo
1. Run start.sh
2. This will start a TCP server (localhost:3333) by default.
3. Connect to the server by using telnet. (eg: "telnet localhost 3333")
4. Input lat and lon seperated by comma, returns 3 letter country code and time taken to respond in nanoseconds.
## Compiling
To compile, run:
``` bash
go build src/server.go
```
To compile for a Linux machine from Mac, run (with correct architecture):
``` bash
env GOOS=linux GOARCH=amd64 go build src/server.go
```
## Testing
To test, run:
```
go test
```
## Example
Starting the server:
``` bash
$ sh start.sh
2016/08/18 23:30:07 Creating server with address localhost:3333
2016/08/18 23:30:07 Loading data..
2016/08/18 23:30:13 Loading complete.
2016/08/18 23:30:13 Total Entries: 5235316
2016/08/18 23:30:13 Boot time: 5 seconds
```
``` bash
$ telnet 127.0.0.1 3333
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
12,77
IND,17176
```
## Data
The world boundaries were generated using QGIS, converted to a set of ~350 million geohashes at precision level 6 and then reduced (compressed) to a set of ~5 million geohashes using [georaptor](https://github.com/ashwin711/georaptor).
## Contributors
Sooraj B - [@soorajb](http://github.com/soorajb)
Ashwin Nair - [@ashwin711](http://github.com/ashwin711)
Harikrishnan Shaji - [@har777](http://github.com/har777)
## License
MIT License
================================================
FILE: bin/.keep
================================================
================================================
FILE: build_linux.sh
================================================
env GOOS=linux GOARCH=amd64 go build src/server.go
================================================
FILE: data/.keep
================================================
================================================
FILE: src/server.go
================================================
package main
import (
"bufio"
"compress/gzip"
"flag"
"log"
"os"
"strconv"
"strings"
"time"
"github.com/firstrow/tcp_server"
"github.com/mmcloughlin/geohash"
)
var serverHost = flag.String("host", "localhost", "Hostname to bind to. eg: 192.168.1.10, default:localhost")
var serverPort = flag.String("port", "3333", "Port eg: 8080, default: 3333")
var dataPath = flag.String("dataPath", "./data/master.csv.gz", "Path to data file. eg: ./data/file.gz, default: ./data/master.csv.gz")
func main() {
flag.Parse()
connString := *serverHost + ":" + *serverPort
dataFilePath := *dataPath
server := tcp_server.New(connString)
geohashToCountryMapping := getGeohashToCountryMapping(dataFilePath)
server.OnNewMessage(func(c *tcp_server.Client, message string) {
startNano := time.Now().UnixNano()
reply := messageHandler(message, geohashToCountryMapping)
c.Send(reply + "\n")
log.Println("Response time: " + strconv.FormatInt((time.Now().UnixNano()-startNano), 10))
})
server.Listen()
}
func messageHandler(message string, geohashToCountryMapping map[string]string) string {
message = strings.TrimSpace(message)
response := ""
startNano := time.Now().UnixNano()
if message != "" {
lat, lon := parseLatLonFromMessage(message)
geohash6 := generateGeohash(lat, lon)
country := getCountryFromGeohashToCountryMapping(geohash6, geohashToCountryMapping)
timeTaken := time.Now().UnixNano() - startNano
response = country + ", " + strconv.FormatInt(timeTaken, 10)
}
log.Println(message + " => " + response)
return response
}
func getCountryFromGeohashToCountryMapping(geohash6 string, geohashToCountryMapping map[string]string) string {
country := ""
for geohashLength := 6; geohashLength > 1; geohashLength-- {
country = geohashToCountryMapping[geohash6[0:geohashLength]]
if country != "" {
break
}
}
return country
}
func parseLatLonFromMessage(message string) (float64, float64) {
coords := strings.Split(message, ",")
lat, lon := 0.0, 0.0
if len(coords) == 2 {
lat, _ = strconv.ParseFloat(strings.TrimSpace(coords[0]), 64)
lon, _ = strconv.ParseFloat(strings.TrimSpace(coords[1]), 64)
}
return lat, lon
}
func generateGeohash(lat float64, lon float64) string {
return geohash.EncodeWithPrecision(lat, lon, 6)
}
func getGeohashToCountryMapping(filePath string) map[string]string {
geohashToCountryMapping := make(map[string]string)
startNano := time.Now().UnixNano()
log.Println("Loading data.")
file, err := os.Open(filePath)
defer file.Close()
checkError(err)
gzipReader, err := gzip.NewReader(file)
defer gzipReader.Close()
checkError(err)
scanner := bufio.NewScanner(gzipReader)
for scanner.Scan() {
line := strings.Split(scanner.Text(), ",")
geohashToCountryMapping[line[0]] = line[1]
}
checkError(scanner.Err())
log.Println("Loading complete.")
log.Println("Total Entries: " + strconv.Itoa(len(geohashToCountryMapping)))
timeTaken := (time.Now().UnixNano() - startNano) / 1000000000
log.Println("Boot time: " + strconv.FormatInt(timeTaken, 10) + " seconds")
return geohashToCountryMapping
}
func checkError(e error) {
if e != nil {
log.Println(e)
}
}
================================================
FILE: src/server_test.go
================================================
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGenerateGeohash(t *testing.T) {
lat := 12.941084
lon := 77.6099103
expectedGeohash := "tdr1w5"
actualGeohash := generateGeohash(lat, lon)
assert.Equal(t, expectedGeohash, actualGeohash, "Generated geohash doesnt match with expected geohash.")
}
func TestParseLatLonFromMessage1(t *testing.T) {
message := "12.941084,77.6099103"
expectedLat, expectedLon := 12.941084, 77.6099103
actualLat, actualLon := parseLatLonFromMessage(message)
assert.Equal(t, expectedLat, actualLat, "Generated latitude doesnt match with expected latitude.")
assert.Equal(t, expectedLon, actualLon, "Generated longitude doesnt match with expected longitude.")
}
func TestParseLatLonFromMessage2(t *testing.T) {
message := "40.744630, -73.981481"
expectedLat, expectedLon := 40.744630, -73.981481
actualLat, actualLon := parseLatLonFromMessage(message)
assert.Equal(t, expectedLat, actualLat, "Generated latitude doesnt match with expected latitude.")
assert.Equal(t, expectedLon, actualLon, "Generated longitude doesnt match with expected longitude.")
}
func TestGetCountryFromGeohashToCountryMapping(t *testing.T) {
geohash6FromCountryAUS, expectedCountryForAUSGeohash := "qsxtqw", "AUS"
geohash6FromCountryJPN, expectedCountryForJPNGeohash := "xn7735", "JPN"
geohash6FromOcean, expectedCountryForOceanGeohash := "mxty6f", ""
geohashToCountryMapping := make(map[string]string)
geohashToCountryMapping["qsxtqw"] = "AUS"
geohashToCountryMapping["xn7"] = "JPN"
actualCountryForAUSGeohash := getCountryFromGeohashToCountryMapping(geohash6FromCountryAUS, geohashToCountryMapping)
actualCountryForJPNGeohash := getCountryFromGeohashToCountryMapping(geohash6FromCountryJPN, geohashToCountryMapping)
actualCountryForOceanGeohash := getCountryFromGeohashToCountryMapping(geohash6FromOcean, geohashToCountryMapping)
assert.Equal(t, expectedCountryForAUSGeohash, actualCountryForAUSGeohash, "Generated country doesnt match with expected country.")
assert.Equal(t, expectedCountryForJPNGeohash, actualCountryForJPNGeohash, "Generated country doesnt match with expected country.")
assert.Equal(t, expectedCountryForOceanGeohash, actualCountryForOceanGeohash, "Generated country doesnt match with expected country.")
}
func TestGetGeohashToCountryMapping(t *testing.T) {
expectedGeohashToCountryMapping := make(map[string]string)
expectedGeohashToCountryMapping["d6nq9t"] = "ABW"
expectedGeohashToCountryMapping["wh3x0u"] = "IND"
actualGeohashToCountryMapping := getGeohashToCountryMapping("dummy_test_data.csv.gz")
assert.Equal(t, expectedGeohashToCountryMapping, actualGeohashToCountryMapping, "Generated geohashToCountryMapping doesnt match with expected geohashToCountryMapping.")
}
================================================
FILE: start.sh
================================================
nohup ./bin/server -p 3333 > /dev/null &
gitextract_vsbryt61/ ├── .gitignore ├── README.md ├── bin/ │ ├── .keep │ ├── server_amd64 │ └── server_darwin ├── build_linux.sh ├── data/ │ └── .keep ├── src/ │ ├── server.go │ └── server_test.go └── start.sh
SYMBOL INDEX (12 symbols across 2 files)
FILE: src/server.go
function main (line 21) | func main() {
function messageHandler (line 38) | func messageHandler(message string, geohashToCountryMapping map[string]s...
function getCountryFromGeohashToCountryMapping (line 54) | func getCountryFromGeohashToCountryMapping(geohash6 string, geohashToCou...
function parseLatLonFromMessage (line 65) | func parseLatLonFromMessage(message string) (float64, float64) {
function generateGeohash (line 75) | func generateGeohash(lat float64, lon float64) string {
function getGeohashToCountryMapping (line 79) | func getGeohashToCountryMapping(filePath string) map[string]string {
function checkError (line 106) | func checkError(e error) {
FILE: src/server_test.go
function TestGenerateGeohash (line 9) | func TestGenerateGeohash(t *testing.T) {
function TestParseLatLonFromMessage1 (line 17) | func TestParseLatLonFromMessage1(t *testing.T) {
function TestParseLatLonFromMessage2 (line 25) | func TestParseLatLonFromMessage2(t *testing.T) {
function TestGetCountryFromGeohashToCountryMapping (line 33) | func TestGetCountryFromGeohashToCountryMapping(t *testing.T) {
function TestGetGeohashToCountryMapping (line 51) | func TestGetGeohashToCountryMapping(t *testing.T) {
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (8K chars).
[
{
"path": ".gitignore",
"chars": 16,
"preview": ".idea/\ndump.rdb\n"
},
{
"path": "README.md",
"chars": 1612,
"preview": "## Loc2Country\n\nLocation coordinates (lat/lon) to ISO alpha-3 country code. Responds in microseconds.\n\n## Manual\n\nInput "
},
{
"path": "bin/.keep",
"chars": 0,
"preview": ""
},
{
"path": "build_linux.sh",
"chars": 51,
"preview": "env GOOS=linux GOARCH=amd64 go build src/server.go\n"
},
{
"path": "data/.keep",
"chars": 0,
"preview": ""
},
{
"path": "src/server.go",
"chars": 3242,
"preview": "package main\n\nimport (\n \"bufio\"\n \"compress/gzip\"\n \"flag\"\n \"log\"\n \"os\"\n \"strconv\"\n \"strings\"\n \"time\"\n\n \"github.c"
},
{
"path": "src/server_test.go",
"chars": 2808,
"preview": "package main\n\nimport (\n \"testing\"\n\n \"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGenerateGeohash(t *testing.T) {\n "
},
{
"path": "start.sh",
"chars": 41,
"preview": "nohup ./bin/server -p 3333 > /dev/null &\n"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the soorajb/loc2country GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (7.6 KB), approximately 2.4k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.