Skip to content
This repository has been archived by the owner on Jul 22, 2020. It is now read-only.

Commit

Permalink
finished implementing API
Browse files Browse the repository at this point in the history
added basic test script and some documentation
  • Loading branch information
Southclaws committed May 19, 2018
1 parent 9927bb7 commit 866aba0
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 18 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ server_log.txt
#

*.sublime-workspace

iphub_key.inc
44 changes: 41 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,47 @@ Include in your code and begin using the library:
## Usage

When a player connects, their details are automatically requested. Once the
response has arrived, the functions `GetPlayerCountryCode` and
`GetPlayerCountryName` can be used.
response has arrived, the API can be used.

`bool:IsGeoDataReady(playerid)` Checks if the data is ready, requests should
only take milliseconds but this ensures your code doesn't attempt to request
data that isn't ready yet.

The rest of the API corresponds directly to the
[IPHub documentation](https://docs.iphub.info/documentation/json-keys/):

* `GetPlayerCountryCode(playerid, output[], len = sizeof output)`
* `GetPlayerCountryName(playerid, output[], len = sizeof output)`
* `GetPlayerASN(playerid, &asn)`
* `GetPlayerISP(playerid, output[], len = sizeof output)`
* `GetPlayerIPBlock(playerid, &block)`

## Testing

(There are no unit tests yet)
To test, first you must build build the package with the file `iphub_key.inc`
which should consist of:

```pawn
#define IPHUB_KEY your_api_key
```

You can get a free API key from [this page](https://iphub.info/pricing) by
clicking `Looking for the free plan (2000 req/day)? Here!`

Then just run as normal and connect to `localhost:7777`:

```bash
sampctl package run
```

If you connect locally, you'll see no useful data because you'll be sending the
loopback interface address, but a response will still appear:

```bash
text="requesting ip data" addr="127.0.0.1" playerid=0
text="received ip data" request=0 status=200
text="determined target player for ip data" playerid=0
text="extracted ip data for player" code="ZZ" name="Unknown" asn=0 isp="Private/local IP" block=0
```

You can also type `/ip` in-game to see a message containing the data.
148 changes: 136 additions & 12 deletions geoip.inc
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,27 @@
#endif


#if !defined MAX_GEOIP_COUNTRY_CODE
#define MAX_GEOIP_COUNTRY_CODE (4)
#endif

#if !defined MAX_GEOIP_COUNTRY_NAME
#define MAX_GEOIP_COUNTRY_NAME (128)
#endif

#if !defined MAX_GEOIP_ISP_NAME
#define MAX_GEOIP_ISP_NAME (128)
#endif


// E_GEO_DATA matches the iphub response object, minus the IP address itself
enum E_GEO_DATA {
bool:E_GEO_READY, // false if response hasn't arrived yet
E_GEO_CODE[4], // "countryCode": "US",
E_GEO_NAME[128], // "countryName": "United States",
E_GEO_ASN, // "asn": 15169,
E_GEO_ISP[128], // "isp": "GOOGLE - Google Inc.",
E_GEO_BLOCK, // "block": 1
bool:E_GEO_READY, // false if response hasn't arrived yet
E_GEO_CODE[MAX_GEOIP_COUNTRY_CODE], // "countryCode": "US",
E_GEO_NAME[MAX_GEOIP_COUNTRY_NAME], // "countryName": "United States",
E_GEO_ASN, // "asn": 15169,
E_GEO_ISP[MAX_GEOIP_ISP_NAME], // "isp": "GOOGLE - Google Inc.",
E_GEO_BLOCK, // "block": 1
}

static GeoData[MAX_PLAYERS][E_GEO_DATA];
Expand All @@ -38,23 +51,119 @@ static Map:RequestToPlayer;

forward OnGeoResponse(Request:id, E_HTTP_STATUS:status, Node:node);

stock GetPlayerCountryCode(playerid, output[], len) {
// todo

// -
// API
// -


// IsGeoDataReady checks if geo IP data for a player is ready to read yet.
stock bool:IsGeoDataReady(playerid) {
if(!IsPlayerConnected(playerid)) {
return false;
}
return GeoData[playerid][E_GEO_READY];
}

stock GetPlayerCountryCode(playerid, output[], len = sizeof output) {
if(!IsPlayerConnected(playerid)) {
return 1;
}

if(!GeoData[playerid][E_GEO_READY]) {
return 2;
}

strcat(output, GeoData[playerid][E_GEO_CODE], len);
return 0;
}

stock GetPlayerCountryName(playerid, output[], len) {
// todo
stock GetPlayerCountryName(playerid, output[], len = sizeof output) {
if(!IsPlayerConnected(playerid)) {
return 1;
}

if(!GeoData[playerid][E_GEO_READY]) {
return 2;
}

strcat(output, GeoData[playerid][E_GEO_NAME], len);
return 0;
}

stock GetPlayerASN(playerid, &asn) {
if(!IsPlayerConnected(playerid)) {
return 1;
}

if(!GeoData[playerid][E_GEO_READY]) {
return 2;
}

asn = GeoData[playerid][E_GEO_ASN];
return 0;
}

stock GetPlayerISP(playerid, output[], len = sizeof output) {
if(!IsPlayerConnected(playerid)) {
return 1;
}

if(!GeoData[playerid][E_GEO_READY]) {
return 2;
}

strcat(output, GeoData[playerid][E_GEO_ISP], len);
return 0;
}

stock GetPlayerIPBlock(playerid, &block) {
if(!IsPlayerConnected(playerid)) {
return 1;
}

if(!GeoData[playerid][E_GEO_READY]) {
return 2;
}

block = GeoData[playerid][E_GEO_BLOCK];
return 0;
}


// -
// Internal
// -


hook OnScriptInit() {
Client = RequestsClient("http://v2.api.iphub.info/ip/", RequestHeaders("X-Key", IPHUB_KEY));
new key[] = IPHUB_KEY;
if(strlen(key) == 0) {
fatal("IPHUB_KEY must be set for geoip library");
}

Client = RequestsClient("http://v2.api.iphub.info/ip/", RequestHeaders("X-Key", key));
}

hook OnPlayerConnect(playerid) {
new addr[18];
new addr[16];
GetPlayerIp(playerid, addr, sizeof addr);
_geoip_doRequest(addr, playerid);
}

hook OnPlayerDisconnect(playerid, reason) {
GeoData[playerid][E_GEO_READY] = false;
GeoData[playerid][E_GEO_CODE][0] = EOS;
GeoData[playerid][E_GEO_NAME][0] = EOS;
GeoData[playerid][E_GEO_ASN] = 0;
GeoData[playerid][E_GEO_ISP][0] = EOS;
GeoData[playerid][E_GEO_BLOCK] = 0;
}

_geoip_doRequest(addr[16], playerid) {
dbg("geoip", "requesting ip data",
_s("addr", addr),
_i("playerid", playerid));

new Request:r = RequestJSON(
Client,
Expand All @@ -67,6 +176,10 @@ hook OnPlayerConnect(playerid) {
}

public OnGeoResponse(Request:id, E_HTTP_STATUS:status, Node:node) {
dbg("geoip", "received ip data",
_i("request", _:id),
_i("status", _:status));

if(status != HTTP_STATUS_OK) {
err("iphub response status code was not OK",
_i("status", _:status));
Expand All @@ -78,6 +191,9 @@ public OnGeoResponse(Request:id, E_HTTP_STATUS:status, Node:node) {
return;
}

dbg("geoip", "determined target player for ip data",
_i("playerid", playerid));

// {
// "ip": "8.8.8.8",
// "countryCode": "US",
Expand All @@ -93,4 +209,12 @@ public OnGeoResponse(Request:id, E_HTTP_STATUS:status, Node:node) {
JsonGetInt(node, "asn", GeoData[playerid][E_GEO_ASN]);
JsonGetString(node, "isp", GeoData[playerid][E_GEO_ISP], 128);
JsonGetInt(node, "block", GeoData[playerid][E_GEO_BLOCK]);

dbg("geoip", "extracted ip data for player",
_s("code", GeoData[playerid][E_GEO_CODE]),
_s("name", GeoData[playerid][E_GEO_NAME]),
_i("asn", GeoData[playerid][E_GEO_ASN]),
_s("isp", GeoData[playerid][E_GEO_ISP]),
_i("block", GeoData[playerid][E_GEO_BLOCK])
);
}
38 changes: 35 additions & 3 deletions test.pwn
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
#define IPHUB_KEY "123"

#include "iphub_key"
#include "geoip"

main() {
//
logger_debug("geoip", true);
}

public OnPlayerCommandText(playerid, cmdtext[]) {
if(!strcmp(cmdtext, "/ip")) {
if(!IsGeoDataReady(playerid)) {
SendClientMessage(playerid, -1, "Data not ready yet...");
return 1;
}

new
code[MAX_GEOIP_COUNTRY_CODE],
name[MAX_GEOIP_COUNTRY_NAME],
asn,
isp[MAX_GEOIP_ISP_NAME],
block,
str[128];

GetPlayerCountryCode(playerid, code);
GetPlayerCountryName(playerid, name);
GetPlayerASN(playerid, asn);
GetPlayerISP(playerid, isp);
GetPlayerIPBlock(playerid, block);

format(str, sizeof str,
"Country: %s (%s), ASN: %d, ISP: '%s', Block: %d",
name, code, asn, isp, block);

SendClientMessage(playerid, -1, str);

return 1;
}

return 0;
}

0 comments on commit 866aba0

Please sign in to comment.