Skip to content
This repository has been archived by the owner on Mar 1, 2023. It is now read-only.

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Minizbot2012 committed Jul 2, 2020
0 parents commit 5e15844
Show file tree
Hide file tree
Showing 9 changed files with 560 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
auth_config.json
twitch_code.txt
.cav_token.txt
.idea
test/twitch_code.txt
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Modmuss50

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# CAV2

Curse Api Version 2 - in go
Fork-mirror from [Modmuss50/cav2](https://github.com/modmuss50/CAV2)
Extended and cleaned by me (Mini)
Use the [Twitch OAuth Generator](https://twitchapps.com/tmi/) to get your oauth token
159 changes: 159 additions & 0 deletions addon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package cav2

import (
"encoding/json"
"fmt"
"io/ioutil"
"strconv"
)

const (
//APIEndpoint URL of API
APIEndpoint = "https://addons-ecs.forgesvc.net/api/v2/"
)

var (
//EMPTY Empty req data
EMPTY []byte
)

//GetAddon gets Addon with addonID
func GetAddon(addonID string) (*Addon, error) {
response, err := GetHTTPResponse("GET", getAPI()+"addon/"+addonID, EMPTY)
if err != nil {
return nil, err
}

var addonResponse *Addon
err = json.NewDecoder(response.Body).Decode(&addonResponse)
if err != nil {
return nil, err
}
return addonResponse, nil
}

//GetAddons Gets addons with []AddonID
func GetAddons(addons []int) ([]*Addon, error) {
jsonPayload, _ := json.Marshal(addons)
response, err := GetHTTPResponse("POST", getAPI()+"addon", jsonPayload)
if err != nil {
return nil, err
}
var addonResponse []*Addon
err = json.NewDecoder(response.Body).Decode(&addonResponse)
if err != nil {
return nil, err
}
return addonResponse, nil
}

//GetAddonFile Gets an addons file with AddonID and fileId
func GetAddonFile(addon int, fileID int) (*File, error) {
response, err := GetHTTPResponse("GET", getAPI()+"addon/"+strconv.Itoa(addon)+"/file/"+strconv.Itoa(fileID), EMPTY)
if err != nil {
return nil, err
}
var addonResponse *File
err = json.NewDecoder(response.Body).Decode(&addonResponse)
if err != nil {
return nil, err
}
return addonResponse, nil
}

//GetAddonFiles Gets files for addonID
func GetAddonFiles(addonID string) ([]*File, error) {
response, err := GetHTTPResponse("GET", getAPI()+"addon/"+addonID+"/files", EMPTY)
if err != nil {
return nil, err
}

var addonResponse []*File
err = json.NewDecoder(response.Body).Decode(&addonResponse)
if err != nil {
return nil, err
}
return addonResponse, nil
}

//GetHashMatches Gets addon Fingerprints
func GetHashMatches(addons []int) (*FingerprintList, error) {
jsonPayload, _ := json.Marshal(addons)
response, err := GetHTTPResponse("POST", APIEndpoint+"fingerprint", jsonPayload)
if err != nil {
return nil, err
}
var addonResponse *FingerprintList
err = json.NewDecoder(response.Body).Decode(&addonResponse)
if err != nil {
return nil, err
}
return addonResponse, nil
}

//GetAddonDatabaseTimestamp Gets last update of addon DB
func GetAddonDatabaseTimestamp() (string, error) {
response, err := GetHTTPResponse("GET", getAPI()+"addon/timestamp", EMPTY)
if err != nil {
return "", err
}

bodyBytes, _ := ioutil.ReadAll(response.Body)
bodyString := string(bodyBytes)

return bodyString, nil
}

//Search searches for addons with query
func Search(query string) ([]*Addon, error) {
//TODO expand this to allow more things to be searched for
//"api/addon/search?gameId={0}&sectionId={1}&categoryId={2}&gameVersion={3}&index={4}&pageSize={5}&searchFilter={6}&sort={7}&sortDescending={8}"
seachPayload := "?gameId=432&sectionId=-1&categoryId=-1&index=0&pageSize=1000&sort=TotalDownloads&sortDescending=true&searchFilter=" + query
response, err := GetHTTPResponse("GET", getAPI()+"addon/search"+seachPayload, EMPTY)
if err != nil {
return nil, err
}
var addonResponse []*Addon
err = json.NewDecoder(response.Body).Decode(&addonResponse)
if err != nil {
return nil, err
}
return addonResponse, nil
}

//GetAllAddons Uses the search to find as many addons as possible, not perfect but should get most of them.
//This is a very expensive call, takes a while and uses a lot of api requests
func GetAllAddons() ([]*Addon, error) {
allAddons := make([]*Addon, 0)

lastFind := 1000
index := 0
for lastFind == 1000 {
if index > 100 {
fmt.Println("Breaking out index too big")
break
}
seachPayload := "?gameId=432&sectionId=6&categoryId=0&index=" + strconv.Itoa(len(allAddons)) + "&searchFilter=&pageSize=1000&sort=5"
response, err := GetHTTPResponse("GET", APIEndpoint+"addon/search"+seachPayload, EMPTY)
if err != nil {
fmt.Println(err.Error())
return nil, err
}
var addonResponse []*Addon
err = json.NewDecoder(response.Body).Decode(&addonResponse)
if err != nil {
fmt.Println(err.Error())
return nil, err
}

lastFind = len(addonResponse)
index++
allAddons = append(allAddons, addonResponse...)
}

return allAddons, nil
}

func getAPI() string {
return APIEndpoint
}
23 changes: 23 additions & 0 deletions cav2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package cav2

var (
//OAuthToken - Twitch oauth's token
OAuthToken string
//WriteSession - Unknown
WriteSession = false
)

const (
twitchCodeFile = "twitch_code.txt"
)

//SetOAuth Takes in a twitch oauth code generated with OAuth.html
func SetOAuth(token string) {
OAuthToken = token
}

//ReadTokenFromDisk Reads the auth token from a file
func ReadTokenFromDisk() {
code := readStringFromFile(twitchCodeFile)
SetOAuth(code)
}
61 changes: 61 additions & 0 deletions http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cav2

import (
"bytes"
"errors"
"io/ioutil"
"net/http"
"strings"
)

//GetHTTPResponse gets response from URL (Wraps GetAuthenicatedResponse)
func GetHTTPResponse(method, url string, b []byte) (*http.Response, error) {
return GetAuthenticatedReponse(method, OAuthToken, url, b)
}

//GetAuthenticatedReponse wraps an http client with an authenication token
func GetAuthenticatedReponse(method, token, url string, b []byte) (*http.Response, error) {
client := &http.Client{}

req, err := http.NewRequest(method, url, bytes.NewReader(b))
if err != nil {
return nil, err
}

if len(token) > 0 && strings.HasPrefix(url, APIEndpoint) {
req.Header.Add("AuthenticationToken", token)
}
req.Header.Add("Content-Type", "application/json")

resp, err := client.Do(req)

if resp.StatusCode != http.StatusOK {
return resp, errors.New(resp.Status)
}

return resp, err
}

//DoHTTPRequest does a basic http request
func DoHTTPRequest(url string) (*http.Response, error) {
client := &http.Client{}
req, err := http.NewRequest("GET", url, bytes.NewReader(EMPTY))
resp, err := client.Do(req)
if resp.StatusCode != http.StatusOK {
return resp, errors.New(resp.Status)
}
return resp, err
}

//ResponseToBytes Converts an http.Response to bytes
func ResponseToBytes(response *http.Response) []byte {
bodyBytes, _ := ioutil.ReadAll(response.Body)
return bodyBytes
}

//ResponseToString Converts an http.Response to a string
func ResponseToString(response *http.Response) string {
bodyBytes, _ := ioutil.ReadAll(response.Body)
bodyString := string(bodyBytes)
return bodyString
}
36 changes: 36 additions & 0 deletions murmur.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cav2

import (
"io/ioutil"

"github.com/aviddiviner/go-murmur"
)

//GetByteArrayHash Computes a murmur2 byte array hash
func GetByteArrayHash(bytes []byte) int {
return int(murmur.MurmurHash2(computeNormalizedArray(bytes), 1))
}

//GetFileHash Computes a murmur2 hash of a file
func GetFileHash(file string) (int, error) {
bytes, err := ioutil.ReadFile(file)
if err != nil {
return 0, err
}
result := GetByteArrayHash(bytes)
return result, nil
}

func computeNormalizedArray(bytes []byte) []byte {
var newArray []byte
for _, byte := range bytes {
if !isWhitespaceCharacter(byte) {
newArray = append(newArray, byte)
}
}
return newArray
}

func isWhitespaceCharacter(b byte) bool {
return b == 9 || b == 10 || b == 13 || b == 32
}
Loading

0 comments on commit 5e15844

Please sign in to comment.