Getting Started - swgoh-utils/swgoh-comlink GitHub Wiki
See the wiki homepage to learn more about getting assets, stats, and using Comlink with Google Sheets.
SWGoH Comlink is provided in several ways:
-
Docker Image: An executable docker image can be obtained via the github container registry at
ghcr.io/swgoh-utils/swgoh-comlink:latest
. This image can be imported into Docker↗ or any other container runtime environment that accepts Docker Images. The docker image is multiplatform and can support amd64, x64, and arm64. - Binary executable: A binary can be downloaded from github↗. Binaries are provided on a best effort basis with each release.
It is recommended to run Comlink as a container.
-
APP_NAME
| Required
The name of your tool/application that will be used to identify your tool in the requests sent to the games APIs. Can also be specified using the--name
or-n
flag at the command line, but the environment variable method is recommended. -
PORT
| Optional
Specifies which port to expose. Default is3000
. Can also be specified using the--port
or-p
flag at the command line. The chosen number is more important to set when not using Docker. When running using docker it doesn't matter as much, you just need to set the external port. -
ACCESS_KEY
| Optional
Used as the "public" key in the HMAC signing process, using this will limit access to only those with the valid keys. -
SECRET_KEY
| Optional
Used as the "private" key in the HMAC signing process, using this will limit access to only those with the valid keys. -
HMAC_MAX_DRIFT
| Optional
The amount of time you would like a request to be valid for, in seconds (in the future). Used with HMAC signing process to adjust timestamps if receiving errors. Defaults to30
seconds. -
HMAC_MIN_DRIFT
| Optional
The amount of time you would like a request to be valid for, in seconds (in the past). Used with HMAC signing process to adjust timestamps if receiving errors. Defaults to-30
seconds. -
LOG_LEVEL
| Optional
The level of logging to surface. Valid values are:error
,warn
,info
, anddebug
. Default isinfo
.
The ci/cd process automatically publishes images to the github container registry.
Updated images can be pulled and deployed directly from the registry. Existing containers should be stopped and removed using a process similar to the below.
docker pull ghcr.io/swgoh-utils/swgoh-comlink:latest
docker stop swgoh-comlink
docker rm swgoh-comlink
docker run --name swgoh-comlink \
-d \
--restart always \
--network swgoh-comlink \
--env APP_NAME=your-app-name-goes-here \
-p 3200:3000 \
ghcr.io/swgoh-utils/swgoh-comlink:latest
If the port from the example above (3200) is already in use in your environment, you can expose the service on a different port by changing the first port number, which is the external port that the internal port maps to.
The -d
option instructs docker to run as a daemon, and --restart always
makes it so that the container will always start with docker / restart if it crashes.
If you are going to be running other services from the swgoh-utils projects and want them to be able to talk to each other directly on the same network, it's convenient to create a network for them such as docker network create swgoh-comlink
. This way they can address each other using the service name and internal ports, such as http://swgoh-comlink:3000
rather than using the public IP address of your host, such as http://192.168.1.100:3200
.
If you do not want to use Docker to create your own applications and would like to just instantly host the service as is on a hosting service you can use the following repos to help you quickly add it and get started.
SWGOH Comlink
SWGOH Stats
You could also run the api on your local machine from Terminal or Command Line using the executable file. To do this you would download the release version for your system and run the program from the command line/terminal setting the name environment variable. This can be done in the following ways:
1. file path/swgoh-comlink-version.exe -n "Your app name"
2. file path/swgoh-comlink-version.exe -name "Your app name"
3.
SET APP_NAME="Your app name" (windows)
or
EXPORT APP_NAME="Your app name" (mac)
file path/swgoh-comlink-version.exe
To set other environment variables you would use the SET or EXPORT keywords:
SET ACCESS_KEY="your-key"
SET SECRET_KEY="your-key"
or
EXPORT ACCESS_KEY=your-key
EXPORT SECRET_KEY=your-key
To prevent tampering with messages, replay attacks, or unauthorized access, an implementation of hash message authentication code (HMAC) is provided. By default it is disabled, unless the environment variables SECRET_KEY and ACCESS_KEY are provided. Any clients authorized to use the service must also have a copy of these values to use to sign and send messages.
The implementation used here is similar to AWS4, but simplified the request
header must include the Authorization header in the format of:
HMAC-SHA256 Credential=<access key goes here>,Signature=<message signature goes here>
The X-Date header must include the timestamp for when the message was generated in unix epoch time format.
The SHA256 hash algorithm is used, using the secret key.
The HMAC should add these attributes of the message in this order:
- request time (the same value as in the X-Date header)
- request method (the verb such as GET or POST)
- request path (the API path, such as /metadata)
- the md5 hash of the request body in hex format. If the request body is empty, use the empty string. Otherwise, hash the stringified version of the JSON request.
The hex digest of this process should be included as the Signature in the Authorization header.
For convenience, the node client stub implements a compliant version of HMAC if it is initialized with the access key and secret to use.
If there is a significant transmission delay between your client and server, or the system clock times do not match, you may need to adjust the max/min drift environment variables to allow more tolerance for the difference in timestamps so that the messages are accepted.
There is an openapi.json file and Redoc UI interface (api-docs) served from the service that can be accessed from a web browser at http://localhost:3000/ where 3000 is the port number you have it set to. They both contain the same information discussing the endpoints and schemas the api has.
Detailed information about the returned data, examples of using it, and ways to parse it can be found on these wiki pages:
Returns an object containing all of the game data enums.
Request Method: GET
Returns the metadata for the game.
Request Method: POST
payload
Object | Optional
The object containing request information. Contains clientSpecs.
payload.clientSpecs
Object | Optional
The object containing client specifications to return the metadata for. Contains: platform, bundleId, externalVersion, internalVersion, region.
payload.clientSpecs.platform
String | Optional
The device platform.
payload.clientSpecs.bundleId
String | Optional
The bundle ID.
payload.clientSpecs.externalVersion
String | Optional
The external version.
payload.clientSpecs.internalVersion
String | Optional
The internal version.
payload.clientSpecs.region
String | Optional
The region.
enums
Boolean | Optional
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"payload": {
"clientSpecs": {
"platform": "Android",
"bundleId": "string",
"externalVersion": "string",
"internalVersion": "string",
"region": "string"
}
},
"enums": false
}
Returns multiple objects containing values for names and descriptions for several different languages.
Request Method: POST
payload
Object
The object containing request information. Contains id.
payload.id
String
The localization version being requested. The latest localization version will always be found in the metadata endpoint in the key "latestLocalizationBundleVersion".
unzip
Boolean
Indicates if you want the data should be returned as a zipped file.
enums
Boolean | Optional
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"payload": {
"id": "AfjAusw7RraFX011_Kwi2Q"
},
"unzip": true
}
Returns multiple objects containing various different game data. The data can be returned in one large request or in multiple small requests.
Request Method: POST
payload
Object
The object containing request information. Contains version, includePveUnits and requestSegment.
payload.version
String
The game data version being requested. The latest game version will always be found in the /metadata
endpoint in the key "latestGamedataVersion".
payload.includePveUnits
Boolean
Specifies whether you want the game data to include NPC unit information. Currently this option only affects the NPC information found within the units object.
payload.requestSegment
Integer
Used to indicate if you want all of the data at once or to request it in pieces. For detailed information on the returned data see the Game Data page.
0
= All data, 200+ MB
1
= Partial data A, about 50 MB
2
= Partial data B, about 50 MB
3
= Partial data C, 80+ MB, 50+ MB with includePveUnits: false
4
= Partial data D, 25+ MB
enums
Boolean
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"payload": {
"version": "0.28.6:benKkOetTsaMZVWKY4E-LA",
"includePveUnits": true,
"requestSegment": 0
},
"enums": false
}
Returns a players profile including roster.
Request Method: POST
payload
Object
The object containing request information. Contains allyCode and/or playerId.
payload.allyCode
String
The ally code of the player you want the profile of.
payload.playerId
String | Optional
The player ID of the player you want the profile of.
enums
Boolean
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"payload": {
"allyCode": "596966614"
},
"enums": false
}
Returns only a players arena profile. Includes Squad Arena, Fleet Arena, and Grand Arena.
Request Method: POST
payload
Object
The object containing request information. Contains allyCode and/or playerId.
payload.allyCode
String
The ally code of the player you want the profile of.
payload.playerId
String | Optional
The player ID of the player you want the profile of.
enums
Boolean
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"payload": {
"allyCode": "596966614"
},
"enums": false
}
Returns a guild profile.
Request Method: POST
payload
Object
The object containing request information. Contains guildId and includeRecentGuildActivityInfo.
payload.guildId
String
The guild id you want the profile of.
payload.includeRecentGuildActivityInfo
Boolean | Optional
Indicates including more info on recent guild events and members. Setting this to false will only include player ids for members. Default is false.
enums
Boolean
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"payload": {
"guildId": "jrl9Q-_CRDGdMyNjTQH1rQ",
"includeRecentGuildActivityInfo": true
},
"enums": false
}
Searches for a guild based on criteria or name and then returns a small version of the guild(s) profile(s) that includes the guild id.
Request Method: POST
payload
Object
The object containing request information. The properties this object will use will change depending upon which search method you choose. It will always contain filterType, startIndex, and count. For searches by name it will contain name, for searches by criteria it will also contain searchCriteria.
payload.filterType
Number
The type of search you want to perform.
4
= Search by name
5
= Search by criteria
payload.startIndex
Number | INACTIVE
Indicates which character to start at when doing a search by name. Currently this property is ignored by the game's server. Default is 0.
payload.count
Number | Optional
Indicates up-to how many guild results to return. Default is 10, max is 10,000.
payload.name
String | Required for names
The guild name or a portion of the guild name to search for. Searches are not case sensitive.
payload.searchCriteria
Object | Required for searches
The object containing the criteria information to search for. Contains the properties minMemberCount, maxMemberCount, includeInviteOnly, minGuildGalacticPower, maxGuildGalacticPower, and recentTbParticipatedIn.
payload.searchCriteria.minMemberCount
Number | Optional
The minimum number of members already in the guild. Default is 1.
payload.searchCriteria.maxMemberCount
Number | Optional
The maximum number of members already in the guild. Default is 50.
payload.searchCriteria.includeInviteOnly
Boolean | Optional
Indicates including guilds that are set to invite only. Default is true.
payload.searchCriteria.minGuildGalacticPower
Number | Optional
The minimum total galactic power the guild is at. Default is 1.
payload.searchCriteria.maxGuildGalacticPower
Number | Optional
The maximum total galactic power the guild is at. Default is 500,000,000.
payload.searchCriteria.recentTbParticipatedIn
Array | Optional
An array of the Territory Battle id(s) that the guild has recently done.
enums
Boolean
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"payload": {
"filterType": 5,
"count": 10,
"searchCriteria": {
"minGuildGalacticPower": 430000000,
"recentTbParticipatedIn": ["T05D"]
}
},
"enums": false
}
Returns a list of all events that are currently displayed and scheduled to appear in-game. This excludes all guild events and Proving Grounds, but will include all Training events, Journey Guide events and several instances of GAC. It typically has events up to 5-10 days out and certain surprise events such as new Legendary Events will only show up after the devs announce them and add it to the in-game event list. It allows for seeing the start and end-time of the events along with unlock requirements a few other details.
Request Method: POST
enums
Boolean | Optional
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"enums": false
}
Returns the specified player leaderboard. Currently only returns the following two leaderboards:
- GAC global top 50 leaderboard by league and division
- GAC bracket leaderboards
Note: The GAC bracket leaderboards are only available while the event is going. The brackets will load over time and not always in sequential order. It is best to repeat searching through each league until you are certain you have the last bracket number.
Request Method: POST
payload
Object
The object containing request information. The properties this object will use will change depending upon which leaderboard you want. It will always contain leaderboardType. For GAC Bracket leaderboards it will contain eventInstanceId and groupId, for GAC league leaderboards it will also contain league and division.
payload.leaderboardType
Number
The type of leaderboard you want to get.
4
= GAC bracket leaderboards NOTE: Only available during GAC
6
= GAC top 50 league and division leaderboards
payload.eventInstanceId
String | Required for bracket
Specifies the GAC season you want to get. Consists of the event "id" and "instance" id which can be found in /getEvents
endpoint from the gac event data with a type = 10.
Example = CHAMPIONSHIPS_GRAND_ARENA_GA2_EVENT_SEASON_36:O1676412000000
Event Id = CHAMPIONSHIPS_GRAND_ARENA_GA2_EVENT_SEASON_36
Instance Id = O1676412000000
payload.groupId
String | Required for bracket
Specifies the bracket group to get. Consists of the eventInstanceId above along with the league name and bracket number separated by :. Brackets start at 0 and go up from there.
Example = CHAMPIONSHIPS_GRAND_ARENA_GA2_EVENT_SEASON_36:O1676412000000:KYBER:100
payload.league
Number | Required for GAC top 50
The league id you are trying to get.
20
= Carbonite
40
= Bronzium
60
= Chromium
80
= Aurodium
100
= Kyber
payload.division
Number | Required for GAC top 50
The division id you are trying to get.
5
= Division 5
10
= Division 4
15
= Division 3
20
= Division 2
25
= Division 1
enums
Boolean
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"payload": {
"leaderboardType": 4,
"eventInstanceId": "CHAMPIONSHIPS_GRAND_ARENA_GA2_EVENT_SEASON_36:O1676412000000",
"groupId": "CHAMPIONSHIPS_GRAND_ARENA_GA2_EVENT_SEASON_36:O1676412000000:KYBER:100"
},
"enums": false
}
{
"payload": {
"leaderboardType": 6,
"league": 100,
"division": 25
},
"enums": false
}
Returns the specified guild leaderboard.
Request Method: POST
payload
Object
The object containing request information. It will always contain leaderboardId and count.
payload.leaderboardId
Array
An array of objects containing the properties needed for the request. The properties needed will vary by leaderboard but they all contain leaderboardType and monthOffset.
payload.leaderboardId.leaderboardType
Number
The leaderboard id you want to get.
0
= Total Raid Points NOTE: Adds up all raids
2
= Raid Points (LEGACY)NOTE: This uses the old way to calculate leaderboard and returns incorrect data now
3
= Galactic Power
4
= Territory Battle NOTE: Based on stars
5
= Territory Wars NOTE: Accumulation of defeated GP
6
= Spcific Raid Points
payload.leaderboardId.monthOffset
Number | Optional
Used to indicate getting the current month or previous month data.
0
= Current month data
1
= Previous month data
payload.leaderboardId.defId
String | Required for leaderboardType 2, 4, 5, 6
Indicates the specific event you want the leaderboard data for.
Raids - Legacy (2)
sith_raid
= Sith Triumverate
rancor
= The Pit
aat
= Tank Takedown
kraytdragon
= Krayt Dragon Hunt
speederbike
= Speeder Bike Pursuit
Territory Battles (4)
t01D
= Rebel Assault
t02D
= Imperial Retaliation
t03D
= Separatist Might
t04D
= Republic Offensive
t05D
= Rise of the Empire
Territory Wars (5)
TERRITORY_WAR_LEADERBOARD
= Territory War
Raids (6)
GUILD:RAIDS:NORMAL_DIFF:RANCOR:DIFF06
= The Pit
GUILD:RAIDS:NORMAL_DIFF:RANCOR:HEROIC80
= Heroic Pit
GUILD:RAIDS:NORMAL_DIFF:AAT:DIFF06
= Tank Takedown
GUILD:RAIDS:NORMAL_DIFF:AAT:HEROIC85
= Heroic Tank Takedown
GUILD:RAIDS:NORMAL_DIFF:SITH_RAID:DIFF06
= Sith Triumverate
GUILD:RAIDS:NORMAL_DIFF:SITH_RAID:HEROIC85
= Heroic Sith Triumverate
GUILD:RAIDS:NORMAL_DIFF:KRAYTDRAGON:DIFF01
= Krayt Dragon Hunt
GUILD:RAIDS:NORMAL_DIFF:ROTJ:SPEEDERBIKE
= Speeder Bike Pursuit\
payload.count
Number | Optional
Indicates up-to how many guild results to return. Default is 200, max is 200.
enums
Boolean | Optional
Indicates if the data should be returned using the enum values instead of assigned integers.
{
"payload" : {
"leaderboardId":[
{
"leaderboardType": 4,
"defId": "t05D",
"monthOffset": 0
}
],
"count": 100
},
"enums": false
}
To test using Postman you will need to first have Comlink running.
Within Postman choose to create a new request. In the address bar put http://localhost:3000/
followed by the endpoint you want to test. The above endpoint documentation will indicate if you should choose POST or GET for the request. You will also find examples of the request body that you can copy and paste directly to Postman.
In Postman under the address bar select Body
, then select the raw
option and change the type in the dropdown menu at the end to JSON
. From there you will just paste the request body directly as is into the textbox.
If the request is too large for your system to process within Postman, instead of choosing Send
, click the down arrow next to it and select Send and Download
. This will place it on your hard drive and you can try opening it with a different application that can handle the file size.
If you enable HMAC signing, you can use postman's pre-request scripts to implement HMAC signing and add the script below to it. Please refer to the postman documentation for how to run the pre-request script for each request in the collection so that you do not need to modify every request.
Alternatively you can just import the following two files into Postman where it everything has already been implemented for you: Collection Import, Environment Import
Use the following steps to modify it to your setup:
- Select the swgoh-comlink environment from the dropdown in the top right.
- Click the Environment Quick Look icon.
- Adjust the host, port, and protocol as needed for your Comlink service.
- If using HMAC enter your access key and secret key.
- Go to the swgoh-comlink Collection and select /metadata and run it. This should automatically assign localization and game version variables in the environment.
- You are ready to test it out.
// Pre-request Script for HMAC signing
function getPath(url) {
var pathRegex = /.+?\:\/\/.+?(\/.+?)(?:#|\?|$)/;
var result = url.match(pathRegex);
return result && result.length > 1 ? result[1] : '';
}
function signPostRequest() {
const accessKey = pm.variables.get("accessKey");
const secretKey = pm.variables.get("secretKey");
if (accessKey && secretKey) {
const reqTime = `${(new Date()).getTime()}`;
// resolve the variables in the raw request body
const Property = require('postman-collection').Property;
const resolvedBody = Property.replaceSubstitutions(pm.request.body.raw || "{}", pm.variables.toObject())
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, secretKey)
hmac.update(reqTime); // request time
hmac.update(request['method']); // verb e.g POST
hmac.update(getPath(request['url'])); // url e.g /authGuest
const hash = CryptoJS.MD5(JSON.stringify(JSON.parse(resolvedBody)));
hmac.update(hash.toString(CryptoJS.enc.Hex))
const hmacDigest = hmac.finalize().toString(CryptoJS.enc.Hex);
pm.request.headers.add({key: 'X-Date', value: reqTime});
pm.request.headers.add({
key: 'Authorization',
value: `HMAC-SHA256 Credential=${accessKey},Signature=${hmacDigest}`
});
}
}
signPostRequest();