4 Commits

7 changed files with 851 additions and 183 deletions

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@ RangerMetrics_x64.h
*.log *.log
settings.json settings.json
!*.example

View File

@@ -0,0 +1,15 @@
{
"influxdb": {
"host": "http://host:8086",
"token": "",
"org": "ranger-metrics"
},
"timescaledb": {
"connectionUrl": "postgresql://postgres:password@host:5432/postgres",
"databaseName": "ranger_metrics",
"description": "TimescaleDB is an open-source time-series database built on Postgres. Please leave the final section of the connection URL as 'postgres' as this is the maintenance database name. The extension will connect here first and create the database with desired name, then shift connections to the newly created database to create the schema and conduct write operations."
},
"arma3": {
"refreshRateMs": 1000
}
}

800
arma.go
View File

@@ -9,30 +9,108 @@ package main
import "C" // This is required to import the C code import "C" // This is required to import the C code
import ( import (
"bytes"
"context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io/ioutil"
"log" "log"
"os" "os"
"reflect"
"strconv"
"strings" "strings"
"time" "time"
"unsafe" "unsafe"
influxdb2 "github.com/influxdata/influxdb-client-go/v2" influxdb2 "github.com/influxdata/influxdb-client-go/v2"
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/pgxpool"
) )
var EXTENSION_VERSION string = "0.0.1" // declare list of functions available for call
var AVAILABLE_FUNCTIONS = map[string]interface{}{
"initExtension": initExtension,
"deinitExtension": deinitExtension,
"loadSettings": loadSettings,
"connectToInflux": connectToInflux,
"writeToInflux": writeToInflux,
"connectToTimescale": connectToTimescale,
"initTimescale": initTimescale,
"writeToTimescale": writeToTimescale,
"getDir": getDir,
"sanitizeLineProtocol": sanitizeLineProtocol,
"version": version,
"getUnixTimeNano": getUnixTimeNano,
}
var EXTENSION_VERSION string = "0.0.2"
var extensionCallbackFnc C.extensionCallback var extensionCallbackFnc C.extensionCallback
var influxConnectionSettings influxSettings
var a3Settings arma3Settings type ServerPollSetting struct {
Name string `json:"name"`
Enabled bool `json:"enabled"`
ServerOnly bool `json:"serverOnly"`
IntervalMs int `json:"intervalMs"`
Bucket string `json:"bucket"`
Measurement string `json:"measurement"`
Description string `json:"description"`
}
var ServerPollSettingProperties []string = []string{
"Name",
"Enabled",
"ServerOnly",
"IntervalMs",
"Bucket",
"Measurement",
"Description",
}
type CBAEventHandler struct {
Name string `json:"name"`
Enabled bool `json:"enabled"`
Description string `json:"description"`
}
var CBAEventHandlerProperties []string = []string{
"Name",
"Enabled",
"Description",
}
type settingsJson struct {
Influx struct {
Enabled bool `json:"enabled"`
Host string `json:"host"`
Token string `json:"token"`
Org string `json:"org"`
} `json:"influxdb"`
Timescale struct {
Enabled bool `json:"enabled"`
ConnectionUrl string `json:"connectionUrl"`
DatabaseName string `json:"databaseName"`
} `json:"timescaledb"`
Arma3 struct {
RefreshRateMs int `json:"refreshRateMs"`
Debug bool `json:"debug"`
} `json:"arma3"`
RecordingSettings map[string]interface{} `json:"recordingSettings"`
}
var activeSettings settingsJson
// InfluxDB variables // InfluxDB variables
var DB_CLIENT influxdb2.Client var influxClient influxdb2.Client
// TimescaleDB variables
var timescaleDbPool *pgxpool.Pool
// file paths // file paths
var ADDON_FOLDER string = "./@RangerMetrics" var ADDON_FOLDER string = getDir() + "\\@RangerMetrics"
var LOG_FILE string = ADDON_FOLDER + "/rangermetrics.log" var LOG_FILE string = ADDON_FOLDER + "\\rangermetrics.log"
var SETTINGS_FILE string = ADDON_FOLDER + "/settings.json" var SETTINGS_FILE string = ADDON_FOLDER + "\\settings.json"
var SETTINGS_FILE_EXAMPLE string = ADDON_FOLDER + "\\settings.example.json"
// var BACKUP_FILE_PATH string = ADDON_FOLDER + "/local_backup.log.gzip" // var BACKUP_FILE_PATH string = ADDON_FOLDER + "/local_backup.log.gzip"
// var BACKUP_WRITER *gzip.Writer // var BACKUP_WRITER *gzip.Writer
@@ -46,31 +124,72 @@ func init() {
log.Fatalf("error opening file: %v", err) log.Fatalf("error opening file: %v", err)
} }
// log to console as well // log to console as well
log.SetOutput(io.MultiWriter(f, os.Stdout)) // log.SetOutput(io.MultiWriter(f, os.Stdout))
// log only to file
log.SetOutput(f)
}
func initExtension() {
functionName := "initExtension"
logLine(functionName, `["Initializing RangerMetrics extension", "INFO"]`, false)
logLine(functionName, fmt.Sprintf(`["RangerMetrics Extension Version: %v", "INFO"]`, EXTENSION_VERSION), false)
var err error
activeSettings, err = loadSettings()
if err != nil {
logLine(functionName, fmt.Sprintf(`["Error loading settings: %v", "ERROR"]`, err), false)
return
}
if activeSettings.Influx.Enabled {
influxClient, err = connectToInflux()
if err != nil {
logLine(functionName, fmt.Sprintf(`["Error connecting to InfluxDB: %v", "ERROR"]`, err), false)
return
}
}
if activeSettings.Timescale.Enabled {
timescaleDbPool, err = connectToTimescale()
if err != nil {
logLine(functionName, fmt.Sprintf(`["Error connecting to TimescaleDB: %v", "ERROR"]`, err), false)
return
}
initTimescale()
}
logLine("extensionReady", `["Extension ready", "INFO"]`, false)
}
func deinitExtension() {
functionName := "deinitExtension"
logLine(functionName, `["Deinitializing RangerMetrics extension", "INFO"]`, false)
if timescaleDbPool != nil {
logLine(functionName, `["Closing TimescaleDB connection", "INFO"]`, false)
timescaleDbPool.Close()
} else {
logLine(functionName, `["TimescaleDB connection not open", "INFO"]`, false)
}
logLine(functionName, `[true]`, false)
} }
// func RVExtensionContext(output *C.char, argc *C.int) { // func RVExtensionContext(output *C.char, argc *C.int) {
// } // }
type influxSettings struct { func version() {
Host string `json:"host"` functionName := "version"
Token string `json:"token"` logLine(functionName, fmt.Sprintf(`["RangerMetrics Extension Version:%s", "INFO"]`, EXTENSION_VERSION), false)
Org string `json:"org"`
} }
type arma3Settings struct { // return db client and error
RefreshRateMs int `json:"refreshRateMs"` func connectToInflux() (influxdb2.Client, error) {
} if activeSettings.Influx.Host == "" ||
activeSettings.Influx.Host == "http://host:8086" {
type settingsJson struct { return nil, errors.New("influxConnectionSettings.Host is empty")
Influx influxSettings `json:"influxdb"`
Arma3 arma3Settings `json:"arma3"`
}
func connectToInflux() string {
if influxConnectionSettings.Host == "" {
logLine("connectToInflux", `["influxConnectionSettings.Host is empty", "ERROR"]`)
// logLine("connectToInflux", `["Creating backup file", "INFO"]`) // logLine("connectToInflux", `["Creating backup file", "INFO"]`)
// file, err := os.Open(BACKUP_FILE_PATH) // file, err := os.Open(BACKUP_FILE_PATH)
// if err != nil { // if err != nil {
@@ -83,18 +202,389 @@ func connectToInflux() string {
// logLine("connectToInflux", `["Error creating gzip writer", "ERROR"]`) // logLine("connectToInflux", `["Error creating gzip writer", "ERROR"]`)
// } // }
// return "Error connecting to Influx. Using local backup" // return "Error connecting to Influx. Using local backup"
return "Error connecting to Influx."
} }
DB_CLIENT = influxdb2.NewClientWithOptions(influxConnectionSettings.Host, influxConnectionSettings.Token, influxdb2.DefaultOptions().SetBatchSize(500).SetFlushInterval(2000)) influxClient := influxdb2.NewClientWithOptions(activeSettings.Influx.Host, activeSettings.Influx.Token, influxdb2.DefaultOptions().SetBatchSize(1000).SetFlushInterval(1000))
logLine("connectToInflux", `["DB_CLIENT created", "INFO"]`) return influxClient, nil
return "Connected to Influx successfully"
} }
func deinitialize() { //////////////////////////////////
logLine("deinitialize", `["deinitialize called", "INFO"]`) // TIMESCALE
DB_CLIENT.Close() //////////////////////////////////
func connectToTimescale() (*pgxpool.Pool, error) {
functionName := "connectToTimescale"
var err error
// urlExample := "postgres://username:password@localhost:5432/database_name"
// logLine("connectToTimescale", fmt.Sprintf(`["timescaleConnectionSettings.ConnectionUrl: %s", "INFO"]`, timescaleConnectionSettings.ConnectionUrl))
conn, err := pgx.Connect(context.Background(), activeSettings.Timescale.ConnectionUrl+"/postgres")
if err != nil {
logLine(
functionName,
fmt.Sprintf(`["Error connecting to Timescale DB: %v", "ERROR"]`, err.Error()),
false,
)
return nil, err
}
// ensure database exists
logLine(
functionName,
fmt.Sprintf(`["TimescaleDB: 'CREATE DATABASE %s'", "INFO"]`, activeSettings.Timescale.DatabaseName),
false,
)
conn.Query(context.Background(), fmt.Sprintf(`CREATE DATABASE %s`, activeSettings.Timescale.DatabaseName))
// close connection
conn.Close(context.Background())
// create connection pool
var dbPool *pgxpool.Pool
dbPool, err = pgxpool.Connect(
context.Background(),
fmt.Sprintf(`%s/%s`, activeSettings.Timescale.ConnectionUrl, activeSettings.Timescale.DatabaseName),
)
if err != nil {
logLine(
functionName,
fmt.Sprintf(`["Error connecting to Timescale DB: %v", "ERROR"]`, err.Error()),
false,
)
return nil, err
}
logLine("connectToTimescale", `["Connected to Timescale successfully", "INFO"]`, false)
return dbPool, nil
}
func initTimescale() {
functionName := "initTimescale"
var err error
// schema init sql
var tableCreationSql string = `
CREATE TABLE "Missions" (
"id" serial NOT NULL UNIQUE,
"world_name" VARCHAR(255) NOT NULL,
"briefing_name" VARCHAR(255) NOT NULL,
"mission_name" VARCHAR(255) NOT NULL,
"mission_author" VARCHAR(255) NOT NULL,
"server_name" VARCHAR(255) NOT NULL,
"server_mods" TEXT,
"ace_medical" BOOLEAN NOT NULL,
"radio_tfar" BOOLEAN NOT NULL,
"radio_acre" BOOLEAN NOT NULL,
"start_game" TIMESTAMP NOT NULL,
"start_utc" TIMESTAMP NOT NULL,
"frame_count" FLOAT NOT NULL,
"capture_delay_s" FLOAT NOT NULL,
"addon_ver_major" integer NOT NULL,
"addon_ver_minor" integer NOT NULL,
"addon_ver_patch" integer NOT NULL,
"extension_ver_major" integer NOT NULL,
"extension_ver_minor" integer NOT NULL,
"extension_ver_patch" integer NOT NULL,
"tags" VARCHAR(255) NOT NULL,
CONSTRAINT "Missions_pk" PRIMARY KEY ("id")
) WITH (
OIDS=FALSE
);
CREATE TABLE "Worlds" (
"world_name" VARCHAR(255) NOT NULL,
"display_name" VARCHAR(255) NOT NULL,
"world_size_m" integer NOT NULL,
CONSTRAINT "Worlds_pk" PRIMARY KEY ("world_name")
) WITH (
OIDS=FALSE
);
CREATE TABLE "Units" (
"mission_id" integer NOT NULL,
"unit_id" integer NOT NULL,
"frame" integer NOT NULL,
"steamid64" varchar(100),
"steam_name" VARCHAR(255) NOT NULL,
"a3_profile_name" VARCHAR(255) NOT NULL,
"is_human" BOOLEAN NOT NULL,
"is_afk" BOOLEAN NOT NULL,
"is_alive" BOOLEAN NOT NULL,
"unit_type" VARCHAR(255) NOT NULL,
"role_description" VARCHAR(255),
"side" integer NOT NULL,
"group_id" varchar(100) NOT NULL,
"name" VARCHAR(255),
"position" VARCHAR(255) NOT NULL,
"direction" FLOAT NOT NULL,
"anim_state" varchar(100),
"stance" VARCHAR(255),
"traits" VARCHAR(255),
"damage" FLOAT NOT NULL,
"is_speaking" integer NOT NULL,
CONSTRAINT "Units_pk" PRIMARY KEY ("mission_id","unit_id","frame")
) WITH (
OIDS=FALSE
);
CREATE TABLE "Vehicles" (
"mission_id" integer NOT NULL,
"frame" integer NOT NULL,
"vehicle_id" integer NOT NULL,
"object_type" VARCHAR(255),
"weapons" varchar(3000),
"customization" varchar(1000),
"position" VARCHAR(255) NOT NULL,
"direction" FLOAT NOT NULL,
"vector_dir" varchar(70) NOT NULL,
"vector_up" varchar(70) NOT NULL,
"is_alive" BOOLEAN NOT NULL,
"damage" FLOAT NOT NULL,
CONSTRAINT "Vehicles_pk" PRIMARY KEY ("mission_id","frame","vehicle_id")
) WITH (
OIDS=FALSE
);
CREATE TABLE "Markers" (
"mission_id" integer NOT NULL,
"frame" integer NOT NULL,
"marker_name" VARCHAR(255) NOT NULL,
"data" VARCHAR(255) NOT NULL,
CONSTRAINT "Markers_pk" PRIMARY KEY ("mission_id","frame","marker_name")
) WITH (
OIDS=FALSE
);
CREATE TABLE "Chat" (
"id" serial NOT NULL,
"mission_id" integer NOT NULL,
"sender_id" integer NOT NULL,
"frame" integer NOT NULL,
"timestamp_utc" TIMESTAMP NOT NULL,
"content" VARCHAR(255) NOT NULL,
"channel" integer NOT NULL,
CONSTRAINT "Chat_pk" PRIMARY KEY ("id")
) WITH (
OIDS=FALSE
);
CREATE TABLE "UniqueUsers" (
"steamid64" varchar(100) NOT NULL,
CONSTRAINT "UniqueUsers_pk" PRIMARY KEY ("steamid64")
) WITH (
OIDS=FALSE
);
CREATE TABLE "Environment" (
"mission_id" integer NOT NULL,
"frame" integer NOT NULL,
"date_game" TIMESTAMP NOT NULL,
"date_utc" TIMESTAMP NOT NULL,
"overcast" FLOAT NOT NULL,
"rain" FLOAT NOT NULL,
"humidity" FLOAT NOT NULL,
"fog_value" FLOAT NOT NULL,
"fog_decay" FLOAT NOT NULL,
"fog_base" FLOAT NOT NULL,
"wind_vector" VARCHAR(255) NOT NULL,
"gusts" FLOAT NOT NULL,
"waves" FLOAT NOT NULL,
CONSTRAINT "Environment_pk" PRIMARY KEY ("mission_id","frame")
) WITH (
OIDS=FALSE
);
CREATE TABLE "StaticObjects" (
"mission_id" integer NOT NULL,
"frame" integer NOT NULL,
"building_id" integer NOT NULL,
"position" integer NOT NULL,
"direction" FLOAT NOT NULL,
"vector_dir" varchar(70) NOT NULL,
"vector_up" varchar(70) NOT NULL,
"object_type" VARCHAR(255) NOT NULL,
"classname" VARCHAR(255) NOT NULL,
"simple_object_data" varchar(1500) NOT NULL,
CONSTRAINT "StaticObjects_pk" PRIMARY KEY ("mission_id","frame","building_id")
) WITH (
OIDS=FALSE
);
CREATE TABLE "Campaigns" (
"id" serial NOT NULL,
"name" VARCHAR(255) NOT NULL,
"description" TEXT NOT NULL,
"image" bytea NOT NULL,
CONSTRAINT "Campaigns_pk" PRIMARY KEY ("id")
) WITH (
OIDS=FALSE
);
CREATE TABLE "Missions_In_Campaigns" (
"mission" integer NOT NULL,
"campaign" integer NOT NULL,
CONSTRAINT "Missions_In_Campaigns_pk" PRIMARY KEY ("mission","campaign")
) WITH (
OIDS=FALSE
);
`
relationCreationSql := []string{
`ALTER TABLE "Missions" ADD CONSTRAINT "Missions_fk0" FOREIGN KEY ("world_name") REFERENCES "Worlds"("world_name");`,
`ALTER TABLE "Units" ADD CONSTRAINT "Units_fk0" FOREIGN KEY ("mission_id") REFERENCES "Missions"("id");`,
`ALTER TABLE "Units" ADD CONSTRAINT "Units_fk1" FOREIGN KEY ("steamid64") REFERENCES "UniqueUsers"("steamid64");`,
`ALTER TABLE "Vehicles" ADD CONSTRAINT "Vehicles_fk0" FOREIGN KEY ("mission_id") REFERENCES "Missions"("id");`,
`ALTER TABLE "Markers" ADD CONSTRAINT "Markers_fk0" FOREIGN KEY ("mission_id") REFERENCES "Missions"("id");`,
`ALTER TABLE "Chat" ADD CONSTRAINT "Chat_fk0" FOREIGN KEY ("mission_id") REFERENCES "Missions"("id");`,
`ALTER TABLE "Chat" ADD CONSTRAINT "Chat_fk1" FOREIGN KEY ("sender_id") REFERENCES "Units"("unit_id");`,
`ALTER TABLE "Environment" ADD CONSTRAINT "Environment_fk0" FOREIGN KEY ("mission_id") REFERENCES "Missions"("id");`,
`ALTER TABLE "StaticObjects" ADD CONSTRAINT "StaticObjects_fk0" FOREIGN KEY ("mission_id") REFERENCES "Missions"("id");`,
`ALTER TABLE "Missions_In_Campaigns" ADD CONSTRAINT "Missions_In_Campaigns_fk0" FOREIGN KEY ("mission") REFERENCES "Missions"("id");`,
`ALTER TABLE "Missions_In_Campaigns" ADD CONSTRAINT "Missions_In_Campaigns_fk1" FOREIGN KEY ("campaign") REFERENCES "Campaigns"("id");`,
}
var tx pgx.Tx
tx, err = timescaleDbPool.Begin(context.Background())
if err != nil {
logLine(functionName, fmt.Sprintf(`["Error creating transaction: %v", "ERROR"]`, err.Error()), false)
return
}
_, err = tx.Exec(context.Background(), tableCreationSql)
if err != nil {
logLine(functionName, fmt.Sprintf(`["Error creating tables: %v", "ERROR"]`, err.Error()), false)
tx.Rollback(context.Background())
tx.Commit(context.Background())
return
}
err = tx.Commit(context.Background())
if err != nil {
logLine(functionName, fmt.Sprintf(`["Error committing table creation transaction: %v", "ERROR"]`, err.Error()), false)
return
}
// run each relation creation sql statement
for _, sql := range relationCreationSql {
_, err = tx.Exec(context.Background(), sql)
if err != nil {
logLine(functionName, fmt.Sprintf(`["Error creating relation: %v", "ERROR"]`, err.Error()), false)
tx.Rollback(context.Background())
tx.Commit(context.Background())
return
}
}
err = tx.Commit(context.Background())
if err != nil {
logLine(functionName, fmt.Sprintf(`["Error committing relation creation transaction: %v", "ERROR"]`, err.Error()), false)
return
}
logLine(functionName, `["Timescale schema initialized", "INFO"]`, false)
}
func writeToTimescale(table string, line string) {
// logLine("writeToTimescale", fmt.Sprintf(`["line: %s", "INFO"]`, line))
functionName := "writeToTimescale"
_, err := timescaleDbPool.Exec(context.Background(), "INSERT INTO %1 (time, line) VALUES (NOW(), $2);", table, line)
if err != nil {
logLine(functionName, fmt.Sprintf(`["Error writing to timescale: %v", "ERROR"]`, err.Error()), false)
}
}
func writeToInflux(a3DataRaw *[]string) string {
// convert to string array
a3Data := *a3DataRaw
logLine("writeToInflux", fmt.Sprintf(`["Received %d params", "DEBUG"]`, len(a3Data)), true)
MIN_PARAMS_COUNT := 1
var logData string
functionName := "writeToInflux"
if len(a3Data) < MIN_PARAMS_COUNT {
logData = fmt.Sprintf(`["Not all parameters present (got %d, expected at least %d)", "ERROR"]`, len(a3Data), MIN_PARAMS_COUNT)
logLine(functionName, logData, false)
return logData
}
// use custom bucket or default
var bucket string = fixEscapeQuotes(trimQuotes(string(a3Data[0])))
// Get non-blocking write client
WRITE_API := influxClient.WriteAPI(activeSettings.Influx.Org, bucket)
if WRITE_API == nil {
logData = `["Error creating write API", "ERROR"]`
logLine(functionName, logData, false)
return logData
}
// Get errors channel
errorsCh := WRITE_API.Errors()
go func() {
for writeErr := range errorsCh {
logData = fmt.Sprintf(`["Error parsing line protocol: %s", "ERROR"]`, strings.Replace(writeErr.Error(), `"`, `'`, -1))
logLine(functionName, logData, false)
}
}()
// now we have our write client, we'll go through the rest of the receive array items in line protocol format and write them to influx
for i := 1; i < len(a3Data); i++ {
var p string = fixEscapeQuotes(trimQuotes(string(a3Data[i])))
// write the line to influx
WRITE_API.WriteRecord(p)
// TODO: Add backup writer
// // append backup line to file if BACKUP_WRITER is set
// //
// if BACKUP_WRITER != nil {
// _, err = BACKUP_WRITER.Write([]byte(p + "\n"))
// }
}
// schedule cleanup
WRITE_API.Flush()
logData = fmt.Sprintf(`["Wrote %d lines to influx", "DEBUG"]`, len(a3Data)-1)
logLine(functionName, logData, true)
return "Success"
} }
// sanitize line protocol for influx // sanitize line protocol for influx
@@ -119,10 +609,14 @@ func getDir() string {
return dir return dir
} }
func loadSettings() (dir string, result string, host string) { // return true if the program should continue
logLine("loadSettings", fmt.Sprintf(`["ADDON_FOLDER: %s", "INFO"]`, ADDON_FOLDER)) func loadSettings() (settingsJson, error) {
logLine("loadSettings", fmt.Sprintf(`["LOG_FILE: %s", "INFO"]`, LOG_FILE)) functionName := "loadSettings"
logLine("loadSettings", fmt.Sprintf(`["SETTINGS_FILE: %s", "INFO"]`, SETTINGS_FILE)) logLine(functionName, fmt.Sprintf(`["ADDON_FOLDER: %s", "INFO"]`, ADDON_FOLDER), false)
logLine(functionName, fmt.Sprintf(`["LOG_FILE: %s", "INFO"]`, LOG_FILE), false)
logLine(functionName, fmt.Sprintf(`["SETTINGS_FILE: %s", "INFO"]`, SETTINGS_FILE), false)
settings := settingsJson{}
// print the current working directory // print the current working directory
var file *os.File var file *os.File
@@ -132,59 +626,65 @@ func loadSettings() (dir string, result string, host string) {
// see if the file exists // see if the file exists
if _, err = os.Stat(SETTINGS_FILE); os.IsNotExist(err) { if _, err = os.Stat(SETTINGS_FILE); os.IsNotExist(err) {
// file does not exist // file does not exist
log.Println("settings.json does not exist") logLine(
// create the file functionName,
file, err = os.Create(SETTINGS_FILE) fmt.Sprintf(`["%s does not exist", "ERROR"]`, SETTINGS_FILE),
false,
)
// copy settings.json.example to settings.json
// load contents
fileContents, err := ioutil.ReadFile(SETTINGS_FILE_EXAMPLE)
if err != nil { if err != nil {
log.Fatal(err) return settings, err
} }
defer file.Close() // write contents to settings.json
// write the default settings to the file err = ioutil.WriteFile(SETTINGS_FILE, fileContents, 0644)
ifSet := influxSettings{
Host: "http://localhost:8086",
Token: "my-token",
Org: "my-org",
}
a3Set := arma3Settings{
RefreshRateMs: 1000,
}
defaultSettings := map[string]interface{}{
"influxdb": ifSet,
"arma3": a3Set,
}
encoder := json.NewEncoder(file)
err = encoder.Encode(defaultSettings)
if err != nil { if err != nil {
log.Fatal(err) return settings, err
} }
result = `["settings.json created - please modify!", "WARN"]`
host = ifSet.Host // Exit false to discontinue initialization since settings are defaults
return dir, result, host logLine(functionName, `["CREATED SETTINGS"]`, false)
// return a new error
return settings, errors.New("settings.json does not exist")
} else { } else {
// file exists // file exists
log.Println("settings.json exists") logLine(functionName, `["settings.json found", "DEBUG"]`, true)
// read the file // read the file
file, err = os.Open(SETTINGS_FILE) file, err = os.Open(SETTINGS_FILE)
if err != nil { if err != nil {
log.Fatal(err) return settings, err
} }
defer file.Close() defer file.Close()
decoder := json.NewDecoder(file) decoder := json.NewDecoder(file)
var settings settingsJson
err = decoder.Decode(&settings) err = decoder.Decode(&settings)
if err != nil { if err != nil {
log.Fatal(err) return settings, err
}
// set the settings
influxConnectionSettings = settings.Influx
a3Settings = settings.Arma3
// set the result
result = `["settings.json loaded", "INFO"]`
host = influxConnectionSettings.Host
} }
return dir, result, host // send contents of settings file
// get the file contents
fileContents, err := ioutil.ReadFile(SETTINGS_FILE)
if err != nil {
return settings, err
}
// compact the json
var jsonStr bytes.Buffer
err = json.Compact(&jsonStr, fileContents)
if err != nil {
return settings, err
}
logLine(
"loadSettingsJSON",
jsonStr.String(),
false,
)
}
return settings, nil
} }
func runExtensionCallback(name *C.char, function *C.char, data *C.char) C.int { func runExtensionCallback(name *C.char, function *C.char, data *C.char) C.int {
@@ -217,7 +717,7 @@ func goRVExtensionArgs(output *C.char, outputsize C.size_t, input *C.char, argv
if C.GoString(input) == "sendToInflux" { if C.GoString(input) == "sendToInflux" {
// start a goroutine to send the data to influx // start a goroutine to send the data to influx
// param string is argv[0] which is the data to send to influx // param string is argv[0] which is the data to send to influx
go sendToInflux(&out) go writeToInflux(&out)
temp = fmt.Sprintf("Function: %s nb params: %d", C.GoString(input), argc) temp = fmt.Sprintf("Function: %s nb params: %d", C.GoString(input), argc)
} }
@@ -261,70 +761,7 @@ func fixEscapeQuotes(s string) string {
return strings.Replace(s, `""`, `"`, -1) return strings.Replace(s, `""`, `"`, -1)
} }
func sendToInflux(a3DataRaw *[]string) string { func logLine(functionName string, data string, isDebug bool) {
// convert to string array
a3Data := *a3DataRaw
logLine("sendToInflux", fmt.Sprintf(`["Received %d params", "DEBUG"]`, len(a3Data)))
MIN_PARAMS_COUNT := 1
var logData string
functionName := "sendToInflux"
if len(a3Data) < MIN_PARAMS_COUNT {
logData = fmt.Sprintf(`["Not all parameters present (got %d, expected at least %d)", "ERROR"]`, len(a3Data), MIN_PARAMS_COUNT)
logLine(functionName, logData)
return logData
}
// use custom bucket or default
var bucket string = fixEscapeQuotes(trimQuotes(string(a3Data[0])))
// Get non-blocking write client
WRITE_API := DB_CLIENT.WriteAPI(influxConnectionSettings.Org, bucket)
if WRITE_API == nil {
logData = `["Error creating write API", "ERROR"]`
logLine(functionName, logData)
return logData
}
// Get errors channel
errorsCh := WRITE_API.Errors()
go func() {
for writeErr := range errorsCh {
logData = fmt.Sprintf(`["Error parsing line protocol: %s", "ERROR"]`, strings.Replace(writeErr.Error(), `"`, `'`, -1))
logLine(functionName, logData)
}
}()
// now we have our write client, we'll go through the rest of the receive array items in line protocol format and write them to influx
for i := 1; i < len(a3Data); i++ {
var p string = fixEscapeQuotes(trimQuotes(string(a3Data[i])))
// write the line to influx
WRITE_API.WriteRecord(p)
// TODO: Add backup writer
// // append backup line to file if BACKUP_WRITER is set
// //
// if BACKUP_WRITER != nil {
// _, err = BACKUP_WRITER.Write([]byte(p + "\n"))
// }
}
// schedule cleanup
WRITE_API.Flush()
logData = fmt.Sprintf(`["Wrote %d lines to influx", "INFO"]`, len(a3Data)-1)
logLine(functionName, logData)
return "Success"
}
func logLine(functionName string, data string) {
statusName := C.CString("RangerMetrics") statusName := C.CString("RangerMetrics")
defer C.free(unsafe.Pointer(statusName)) defer C.free(unsafe.Pointer(statusName))
statusFunction := C.CString(functionName) statusFunction := C.CString(functionName)
@@ -333,7 +770,11 @@ func logLine(functionName string, data string) {
defer C.free(unsafe.Pointer(statusParam)) defer C.free(unsafe.Pointer(statusParam))
runExtensionCallback(statusName, statusFunction, statusParam) runExtensionCallback(statusName, statusFunction, statusParam)
if activeSettings.Arma3.Debug && isDebug {
log.Println(data) log.Println(data)
} else if !isDebug {
log.Println(data)
}
} }
//export goRVExtension //export goRVExtension
@@ -341,42 +782,71 @@ func goRVExtension(output *C.char, outputsize C.size_t, input *C.char) {
var temp string var temp string
// logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "DEBUG"]`, C.GoString(input)), true)
switch C.GoString(input) { switch C.GoString(input) {
case "version": case "version":
logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
temp = EXTENSION_VERSION temp = EXTENSION_VERSION
case "getDir": case "getDir":
logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
temp = getDir() temp = getDir()
case "loadSettings":
logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
cwd, result, influxHost := loadSettings()
log.Println("CWD:", cwd)
log.Println("RESULT:", result)
log.Println("INFLUX HOST:", influxHost)
if result != "" {
logLine("goRVExtension", result)
temp = fmt.Sprintf(
`["%s", "%s", "%s", "%d"]`,
EXTENSION_VERSION,
influxConnectionSettings.Host,
influxConnectionSettings.Org,
a3Settings.RefreshRateMs,
)
}
case "connectToInflux":
logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
result := connectToInflux()
temp = fmt.Sprintf(`["%s", "INFO"]`, result)
case "getUnixTimeNano": case "getUnixTimeNano":
temp = fmt.Sprintf(`["%d", "INFO"]`, getUnixTimeNano()) time := getUnixTimeNano()
case "deinitialize": temp = fmt.Sprintf(`["%s"]`, strconv.FormatInt(time, 10))
logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
deinitialize()
temp = `["Deinitializing", "INFO"]`
default: default:
temp = fmt.Sprintf(`["Unknown command: %s", "ERR"]`, C.GoString(input)) // check if input is in AVAILABLE_FUNCTIONS
// if not, return error
// if yes, continue
if _, ok := AVAILABLE_FUNCTIONS[C.GoString(input)]; !ok {
temp = fmt.Sprintf(`["Function: %s not found!", "ERROR"]`, C.GoString(input))
} else {
// call the function by name
go reflect.ValueOf(AVAILABLE_FUNCTIONS[C.GoString(input)]).Call([]reflect.Value{})
temp = fmt.Sprintf(`["Function: %s called successfully", "DEBUG"]`, C.GoString(input))
} }
}
// switch C.GoString(input) {
// case "version":
// logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
// temp = EXTENSION_VERSION
// case "getDir":
// logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
// temp = getDir()
// case "loadSettings":
// logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
// cwd, result, influxHost, timescaleUrl := loadSettings()
// log.Println("CWD:", cwd)
// log.Println("RESULT:", result)
// log.Println("INFLUX HOST:", influxHost)
// log.Println("TIMESCALE URL:", timescaleUrl)
// if result != "" {
// logLine("goRVExtension", result)
// temp = fmt.Sprintf(
// `["%s", "%s", "%s", "%d"]`,
// EXTENSION_VERSION,
// influxConnectionSettings.Host,
// influxConnectionSettings.Org,
// a3Settings.RefreshRateMs,
// )
// }
// case "connectToInflux":
// // logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
// go connectToInflux()
// temp = `["Connecting to InfluxDB", "INFO"]`
// case "connectToTimescale":
// // logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
// go connectToTimescale()
// temp = `["Connecting to TimescaleDB", "INFO"]`
// case "getUnixTimeNano":
// temp = fmt.Sprintf(`["%d", "INFO"]`, getUnixTimeNano())
// case "deinitialize":
// logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
// deinitialize()
// temp = `["Deinitializing", "INFO"]`
// default:
// temp = fmt.Sprintf(`["Unknown command: %s", "ERROR"]`, C.GoString(input))
// }
result := C.CString(temp) result := C.CString(temp)
defer C.free(unsafe.Pointer(result)) defer C.free(unsafe.Pointer(result))

5
go.mod
View File

@@ -2,4 +2,7 @@ module main
go 1.16 go 1.16
require github.com/influxdata/influxdb-client-go/v2 v2.6.0 require (
github.com/influxdata/influxdb-client-go/v2 v2.6.0
github.com/jackc/pgx/v4 v4.18.1
)

179
go.sum
View File

@@ -1,5 +1,13 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU=
github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw=
@@ -7,52 +15,188 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/influxdata/influxdb-client-go/v2 v2.6.0 h1:bIOaGTgvvv1Na2hG+nIvqyv7PK2UiU2WrJN1ck1ykyM= github.com/influxdata/influxdb-client-go/v2 v2.6.0 h1:bIOaGTgvvv1Na2hG+nIvqyv7PK2UiU2WrJN1ck1ykyM=
github.com/influxdata/influxdb-client-go/v2 v2.6.0/go.mod h1:Y/0W1+TZir7ypoQZYd2IrnVOKB3Tq6oegAQeSVN/+EU= github.com/influxdata/influxdb-client-go/v2 v2.6.0/go.mod h1:Y/0W1+TZir7ypoQZYd2IrnVOKB3Tq6oegAQeSVN/+EU=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q=
github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0=
github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw=
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0=
github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk=
github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -61,18 +205,51 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

View File

@@ -1,6 +0,0 @@
{
"host" : "http://INFLUX_URL:8086",
"token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXX_AUTH_TOKEN_XXXXXXXXXXXXXXXXXXXXXXXXXXX",
"org" : "ORG_NAME",
"bucket" : "BUCKET_NAME",
}

View File

@@ -1,18 +1,26 @@
freeExtension "RangerMetrics"; freeExtension "RangerMetrics";
// sleep 0.5; // sleep 0.5;
"RangerMetrics" callExtension "loadSettings"; // "RangerMetrics" callExtension "loadSettings";
// sleep 3;
// "RangerMetrics" callExtension "version"; // "RangerMetrics" callExtension "version";
// sleep 3;
// "RangerMetrics" callExtension "connectToInflux"; // "RangerMetrics" callExtension "connectToInflux";
// // sleep 3; // "RangerMetrics" callExtension "connectToTimescale";
// // sleep 100; // sleep 5;
// "RangerMetrics" callExtension ["sendToInflux", ["server","mission_name","string","tag|profile|IndigoFox","tag|world|altis","tag|source|onLoadName","field|server|IndigoFox on DESKTOP-6B2U0AT","field|mission|aarangermetricstesting","field|value|mission_name"]]; // "RangerMetrics" callExtension "initTimescale";
sleep 30; // addMissionEventHandler ["ExtensionCallback", {
// params ["_extension", "_function", "_data"];
// if (
// _extension == "RangerMetrics" && _function isEqualTo "connectToTimescale"
// ) then {
// diag_log format ["RangerMetrics: %1", _data];
// };
// }];
"RangerMetrics" callExtension "deinitExtension";
sleep 1;
"RangerMetrics" callExtension "initExtension";
sleep 20;
"RangerMetrics" callExtension "deinitExtension";
// freeExtension "RangerMetrics"; // freeExtension "RangerMetrics";
sleep 5;
exit; exit;