Merge branch 'add-mission-details'
This commit is contained in:
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
*.pbo
|
||||
*.bak
|
||||
*.dll
|
||||
|
||||
*.so
|
||||
|
||||
RangerMetrics.h
|
||||
|
||||
RangerMetrics_x64.h
|
||||
|
||||
*.log
|
||||
|
||||
settings.json
|
||||
1015
.vs/Arma3-Influx/config/applicationhost.config
Normal file
1015
.vs/Arma3-Influx/config/applicationhost.config
Normal file
File diff suppressed because it is too large
Load Diff
BIN
.vs/Arma3-Influx/v16/.suo
Normal file
BIN
.vs/Arma3-Influx/v16/.suo
Normal file
Binary file not shown.
BIN
.vs/Arma3-Influx/v16/Browse.VC.db
Normal file
BIN
.vs/Arma3-Influx/v16/Browse.VC.db
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
3
.vs/ProjectSettings.json
Normal file
3
.vs/ProjectSettings.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"CurrentProjectSetting": "x64-Release"
|
||||
}
|
||||
7
.vs/VSWorkspaceState.json
Normal file
7
.vs/VSWorkspaceState.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ExpandedNodes": [
|
||||
""
|
||||
],
|
||||
"SelectedNode": "\\RVExtension.c",
|
||||
"PreviewInSolutionExplorer": false
|
||||
}
|
||||
BIN
.vs/slnx.sqlite
Normal file
BIN
.vs/slnx.sqlite
Normal file
Binary file not shown.
10
.vs/tasks.vs.json
Normal file
10
.vs/tasks.vs.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "0.2.1",
|
||||
"tasks": [
|
||||
{
|
||||
"taskLabel": "task-Arma3-Influx",
|
||||
"appliesTo": "/",
|
||||
"type": "launch"
|
||||
}
|
||||
]
|
||||
}
|
||||
22
README.md
22
README.md
@@ -2,4 +2,24 @@
|
||||
|
||||
A3 extension for sending metrics to InfluxDB using Golang
|
||||
|
||||
> See more: https://github.com/code34/armago_x64
|
||||
## Build
|
||||
|
||||
### Windows
|
||||
|
||||
_Requires Go 1.20.1+ & MinGW_
|
||||
|
||||
```powershell
|
||||
$ENV:GOARCH = "amd64"
|
||||
$ENV:CGO_ENABLED = 1
|
||||
go build -o RangerMetrics_x64.dll -buildmode=c-shared .
|
||||
```
|
||||
|
||||
To validate exported functions:
|
||||
|
||||
```powershell
|
||||
. "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\dumpbin.exe" /exports .\RangerMetrics_x64.dll
|
||||
```
|
||||
|
||||
## Notes
|
||||
>
|
||||
> See more: <https://github.com/code34/armago_x64>
|
||||
|
||||
@@ -4,40 +4,58 @@
|
||||
|
||||
extern void goRVExtension(char *output, size_t outputSize, char *input);
|
||||
extern void goRVExtensionVersion(char *output, size_t outputSize);
|
||||
extern void goRVExtensionArgs(char* output, size_t outputSize, char* input, char** argv, int argc);
|
||||
// extern void goRVExtensionRegisterCallback(extensionCallback fnc);
|
||||
extern void goRVExtensionArgs(char *output, size_t outputSize, char *input, char **argv, int argc);
|
||||
extern void goRVExtensionRegisterCallback(extensionCallback fnc);
|
||||
|
||||
#ifdef WIN64
|
||||
__declspec(dllexport) void RVExtension(char *output, size_t outputSize, char *input) {
|
||||
goRVExtension(output, outputSize, input);
|
||||
__declspec(dllexport) void RVExtension(char *output, size_t outputSize, char *input)
|
||||
{
|
||||
goRVExtension(output, outputSize, input);
|
||||
}
|
||||
|
||||
__declspec(dllexport) void RVExtensionVersion(char *output, size_t outputSize) {
|
||||
goRVExtensionVersion(output, outputSize);
|
||||
__declspec(dllexport) void RVExtensionVersion(char *output, size_t outputSize)
|
||||
{
|
||||
goRVExtensionVersion(output, outputSize);
|
||||
}
|
||||
|
||||
__declspec(dllexport) void RVExtensionArgs(char* output, size_t outputSize, char* input, char** argv, int argc) {
|
||||
goRVExtensionArgs(output, outputSize, input, argv, argc);
|
||||
__declspec(dllexport) void RVExtensionArgs(char *output, size_t outputSize, char *input, char **argv, int argc)
|
||||
{
|
||||
goRVExtensionArgs(output, outputSize, input, argv, argc);
|
||||
}
|
||||
|
||||
//__declspec(dllexport) void RVExtensionRegisterCallback(extensionCallback fnc) {
|
||||
// goRVExtensionRegisterCallback(fnc);
|
||||
//}
|
||||
__declspec(dllexport) void RVExtensionRegisterCallback(extensionCallback fnc)
|
||||
{
|
||||
goRVExtensionRegisterCallback(fnc);
|
||||
}
|
||||
#else
|
||||
__declspec(dllexport) void __stdcall _RVExtension(char *output, size_t outputSize, char *input) {
|
||||
goRVExtension(output, outputSize, input);
|
||||
__declspec(dllexport) void __stdcall _RVExtension(char *output, size_t outputSize, char *input)
|
||||
{
|
||||
goRVExtension(output, outputSize, input);
|
||||
}
|
||||
|
||||
__declspec(dllexport) void __stdcall _RVExtensionVersion(char *output, size_t outputSize) {
|
||||
goRVExtensionVersion(output, outputSize);
|
||||
__declspec(dllexport) void __stdcall _RVExtensionVersion(char *output, size_t outputSize)
|
||||
{
|
||||
goRVExtensionVersion(output, outputSize);
|
||||
}
|
||||
|
||||
__declspec(dllexport) void __stdcall _RVExtensionArgs(char* output, size_t outputSize, char* input, char** argv, int argc) {
|
||||
goRVExtensionArgs(output, outputSize, input, argv, argc);
|
||||
__declspec(dllexport) void __stdcall _RVExtensionArgs(char *output, size_t outputSize, char *input, char **argv, int argc)
|
||||
{
|
||||
goRVExtensionArgs(output, outputSize, input, argv, argc);
|
||||
}
|
||||
|
||||
// __declspec(dllexport) void __stdcall _RVExtensionRegisterCallback(extensionCallback fnc) {
|
||||
// goRVExtensionRegisterCallback(fnc);
|
||||
// }
|
||||
__declspec(dllexport) void __stdcall _RVExtensionRegisterCallback(extensionCallback fnc)
|
||||
{
|
||||
goRVExtensionRegisterCallback(fnc);
|
||||
}
|
||||
#endif
|
||||
// do this for all the other exported functions
|
||||
// do this for all the other exported functions
|
||||
|
||||
// dll entrypoint
|
||||
// Path: RVExtension.c
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BIN
a3influx.dll
BIN
a3influx.dll
Binary file not shown.
Binary file not shown.
87
a3influx.h
87
a3influx.h
@@ -1,87 +0,0 @@
|
||||
/* Code generated by cmd/cgo; DO NOT EDIT. */
|
||||
|
||||
/* package github.com/7cav/a3-fone-home */
|
||||
|
||||
|
||||
#line 1 "cgo-builtin-export-prolog"
|
||||
|
||||
#include <stddef.h> /* for ptrdiff_t below */
|
||||
|
||||
#ifndef GO_CGO_EXPORT_PROLOGUE_H
|
||||
#define GO_CGO_EXPORT_PROLOGUE_H
|
||||
|
||||
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
||||
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Start of preamble from import "C" comments. */
|
||||
|
||||
|
||||
#line 3 "arma.go"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extensionCallback.h"
|
||||
|
||||
#line 1 "cgo-generated-wrapper"
|
||||
|
||||
|
||||
/* End of preamble from import "C" comments. */
|
||||
|
||||
|
||||
/* Start of boilerplate cgo prologue. */
|
||||
#line 1 "cgo-gcc-export-header-prolog"
|
||||
|
||||
#ifndef GO_CGO_PROLOGUE_H
|
||||
#define GO_CGO_PROLOGUE_H
|
||||
|
||||
typedef signed char GoInt8;
|
||||
typedef unsigned char GoUint8;
|
||||
typedef short GoInt16;
|
||||
typedef unsigned short GoUint16;
|
||||
typedef int GoInt32;
|
||||
typedef unsigned int GoUint32;
|
||||
typedef long long GoInt64;
|
||||
typedef unsigned long long GoUint64;
|
||||
typedef GoInt64 GoInt;
|
||||
typedef GoUint64 GoUint;
|
||||
typedef __SIZE_TYPE__ GoUintptr;
|
||||
typedef float GoFloat32;
|
||||
typedef double GoFloat64;
|
||||
typedef float _Complex GoComplex64;
|
||||
typedef double _Complex GoComplex128;
|
||||
|
||||
/*
|
||||
static assertion to make sure the file is being used on architecture
|
||||
at least with matching size of GoInt.
|
||||
*/
|
||||
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
|
||||
|
||||
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
||||
typedef _GoString_ GoString;
|
||||
#endif
|
||||
typedef void *GoMap;
|
||||
typedef void *GoChan;
|
||||
typedef struct { void *t; void *v; } GoInterface;
|
||||
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
|
||||
|
||||
#endif
|
||||
|
||||
/* End of boilerplate cgo prologue. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern __declspec(dllexport) void goRVExtensionVersion(char* output, size_t outputsize);
|
||||
extern __declspec(dllexport) GoInt goRVExtensionArgs(char* output, size_t outputsize, char* input, char** argv, int argc);
|
||||
extern __declspec(dllexport) void goRVExtension(char* output, size_t outputsize, char* input);
|
||||
extern __declspec(dllexport) void goRVExtensionRegisterCallback(extensionCallback fnc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
BIN
a3influx_x64.dll
BIN
a3influx_x64.dll
Binary file not shown.
@@ -1,87 +0,0 @@
|
||||
/* Code generated by cmd/cgo; DO NOT EDIT. */
|
||||
|
||||
/* package github.com/7cav/a3-fone-home */
|
||||
|
||||
|
||||
#line 1 "cgo-builtin-export-prolog"
|
||||
|
||||
#include <stddef.h> /* for ptrdiff_t below */
|
||||
|
||||
#ifndef GO_CGO_EXPORT_PROLOGUE_H
|
||||
#define GO_CGO_EXPORT_PROLOGUE_H
|
||||
|
||||
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
||||
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Start of preamble from import "C" comments. */
|
||||
|
||||
|
||||
#line 3 "arma.go"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extensionCallback.h"
|
||||
|
||||
#line 1 "cgo-generated-wrapper"
|
||||
|
||||
|
||||
/* End of preamble from import "C" comments. */
|
||||
|
||||
|
||||
/* Start of boilerplate cgo prologue. */
|
||||
#line 1 "cgo-gcc-export-header-prolog"
|
||||
|
||||
#ifndef GO_CGO_PROLOGUE_H
|
||||
#define GO_CGO_PROLOGUE_H
|
||||
|
||||
typedef signed char GoInt8;
|
||||
typedef unsigned char GoUint8;
|
||||
typedef short GoInt16;
|
||||
typedef unsigned short GoUint16;
|
||||
typedef int GoInt32;
|
||||
typedef unsigned int GoUint32;
|
||||
typedef long long GoInt64;
|
||||
typedef unsigned long long GoUint64;
|
||||
typedef GoInt64 GoInt;
|
||||
typedef GoUint64 GoUint;
|
||||
typedef __SIZE_TYPE__ GoUintptr;
|
||||
typedef float GoFloat32;
|
||||
typedef double GoFloat64;
|
||||
typedef float _Complex GoComplex64;
|
||||
typedef double _Complex GoComplex128;
|
||||
|
||||
/*
|
||||
static assertion to make sure the file is being used on architecture
|
||||
at least with matching size of GoInt.
|
||||
*/
|
||||
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
|
||||
|
||||
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
||||
typedef _GoString_ GoString;
|
||||
#endif
|
||||
typedef void *GoMap;
|
||||
typedef void *GoChan;
|
||||
typedef struct { void *t; void *v; } GoInterface;
|
||||
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
|
||||
|
||||
#endif
|
||||
|
||||
/* End of boilerplate cgo prologue. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern __declspec(dllexport) void goRVExtensionVersion(char* output, size_t outputsize);
|
||||
extern __declspec(dllexport) GoInt goRVExtensionArgs(char* output, size_t outputsize, char* input, char** argv, int argc);
|
||||
extern __declspec(dllexport) void goRVExtension(char* output, size_t outputsize, char* input);
|
||||
extern __declspec(dllexport) void goRVExtensionRegisterCallback(extensionCallback fnc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
426
arma.go
426
arma.go
@@ -4,16 +4,16 @@ package main
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extensionCallback.h"
|
||||
*/
|
||||
import "C"
|
||||
import "C" // This is required to import the C code
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
@@ -21,7 +21,171 @@ import (
|
||||
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
|
||||
)
|
||||
|
||||
var EXTENSION_VERSION string = "0.0.1"
|
||||
var extensionCallbackFnc C.extensionCallback
|
||||
var influxConnectionSettings influxSettings
|
||||
var a3Settings arma3Settings
|
||||
|
||||
// InfluxDB variables
|
||||
var DB_CLIENT influxdb2.Client
|
||||
|
||||
// file paths
|
||||
var ADDON_FOLDER string = "./@RangerMetrics"
|
||||
var LOG_FILE string = ADDON_FOLDER + "/rangermetrics.log"
|
||||
var SETTINGS_FILE string = ADDON_FOLDER + "/settings.json"
|
||||
|
||||
// var BACKUP_FILE_PATH string = ADDON_FOLDER + "/local_backup.log.gzip"
|
||||
// var BACKUP_WRITER *gzip.Writer
|
||||
|
||||
// configure log output
|
||||
func init() {
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
// log to file
|
||||
f, err := os.OpenFile(LOG_FILE, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Fatalf("error opening file: %v", err)
|
||||
}
|
||||
// log to console as well
|
||||
log.SetOutput(io.MultiWriter(f, os.Stdout))
|
||||
}
|
||||
|
||||
// func RVExtensionContext(output *C.char, argc *C.int) {
|
||||
|
||||
// }
|
||||
|
||||
type influxSettings struct {
|
||||
Host string `json:"host"`
|
||||
Token string `json:"token"`
|
||||
Org string `json:"org"`
|
||||
}
|
||||
|
||||
type arma3Settings struct {
|
||||
RefreshRateMs int `json:"refreshRateMs"`
|
||||
}
|
||||
|
||||
type settingsJson struct {
|
||||
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"]`)
|
||||
// file, err := os.Open(BACKUP_FILE_PATH)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// logLine("connectToInflux", `["Error opening backup file", "ERROR"]`)
|
||||
// }
|
||||
// BACKUP_WRITER = gzip.NewWriter(file)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// logLine("connectToInflux", `["Error creating gzip writer", "ERROR"]`)
|
||||
// }
|
||||
// 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))
|
||||
|
||||
logLine("connectToInflux", `["DB_CLIENT created", "INFO"]`)
|
||||
return "Connected to Influx successfully"
|
||||
}
|
||||
|
||||
func deinitialize() {
|
||||
logLine("deinitialize", `["deinitialize called", "INFO"]`)
|
||||
DB_CLIENT.Close()
|
||||
}
|
||||
|
||||
// sanitize line protocol for influx
|
||||
func sanitizeLineProtocol(line string) string {
|
||||
// replace all spaces with underscores
|
||||
// line = strings.ReplaceAll(line, ` `, `\ `)
|
||||
// replace all commas with underscores
|
||||
// line = strings.ReplaceAll(line, `,`, `\,`)
|
||||
// replace all equals with underscores
|
||||
// line = strings.ReplaceAll(line, "=", "_")
|
||||
// replace all quotes with underscores
|
||||
// line = strings.ReplaceAll(line, "\"", "_")
|
||||
|
||||
return line
|
||||
}
|
||||
|
||||
func getDir() string {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
func loadSettings() (dir string, result string, host string) {
|
||||
logLine("loadSettings", fmt.Sprintf(`["ADDON_FOLDER: %s", "INFO"]`, ADDON_FOLDER))
|
||||
logLine("loadSettings", fmt.Sprintf(`["LOG_FILE: %s", "INFO"]`, LOG_FILE))
|
||||
logLine("loadSettings", fmt.Sprintf(`["SETTINGS_FILE: %s", "INFO"]`, SETTINGS_FILE))
|
||||
|
||||
// print the current working directory
|
||||
var file *os.File
|
||||
var err error
|
||||
// read settings from file
|
||||
// settings.json should be in the same directory as the .dll
|
||||
// see if the file exists
|
||||
if _, err = os.Stat(SETTINGS_FILE); os.IsNotExist(err) {
|
||||
// file does not exist
|
||||
log.Println("settings.json does not exist")
|
||||
// create the file
|
||||
file, err = os.Create(SETTINGS_FILE)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
// write the default settings to the file
|
||||
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 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
result = `["settings.json created - please modify!", "WARN"]`
|
||||
host = ifSet.Host
|
||||
return dir, result, host
|
||||
} else {
|
||||
// file exists
|
||||
log.Println("settings.json exists")
|
||||
// read the file
|
||||
file, err = os.Open(SETTINGS_FILE)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
decoder := json.NewDecoder(file)
|
||||
var settings settingsJson
|
||||
err = decoder.Decode(&settings)
|
||||
if err != nil {
|
||||
log.Fatal(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
|
||||
}
|
||||
|
||||
func runExtensionCallback(name *C.char, function *C.char, data *C.char) C.int {
|
||||
return C.runExtensionCallback(extensionCallbackFnc, name, function, data)
|
||||
@@ -29,7 +193,7 @@ func runExtensionCallback(name *C.char, function *C.char, data *C.char) C.int {
|
||||
|
||||
//export goRVExtensionVersion
|
||||
func goRVExtensionVersion(output *C.char, outputsize C.size_t) {
|
||||
result := C.CString("Version 1.2.3")
|
||||
result := C.CString(EXTENSION_VERSION)
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
@@ -39,14 +203,23 @@ func goRVExtensionVersion(output *C.char, outputsize C.size_t) {
|
||||
}
|
||||
|
||||
//export goRVExtensionArgs
|
||||
func goRVExtensionArgs(output *C.char, outputsize C.size_t, input *C.char, argv **C.char, argc C.int) int {
|
||||
func goRVExtensionArgs(output *C.char, outputsize C.size_t, input *C.char, argv **C.char, argc C.int) {
|
||||
var offset = unsafe.Sizeof(uintptr(0))
|
||||
var out []string
|
||||
for index := C.int(0); index < argc; index++ {
|
||||
out = append(out, C.GoString(*argv))
|
||||
argv = (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + offset))
|
||||
}
|
||||
temp := fmt.Sprintf("Function: %s nb params: %d params: %s!", C.GoString(input), argc, out)
|
||||
|
||||
var temp string
|
||||
temp = fmt.Sprintf("Function: %s nb params: %d params: %s!", C.GoString(input), argc, out)
|
||||
|
||||
if C.GoString(input) == "sendToInflux" {
|
||||
// start a goroutine to send the data to influx
|
||||
// param string is argv[0] which is the data to send to influx
|
||||
go sendToInflux(&out)
|
||||
temp = fmt.Sprintf("Function: %s nb params: %d", C.GoString(input), argc)
|
||||
}
|
||||
|
||||
// Return a result to Arma
|
||||
result := C.CString(temp)
|
||||
@@ -55,8 +228,8 @@ func goRVExtensionArgs(output *C.char, outputsize C.size_t, input *C.char, argv
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
return 1
|
||||
}
|
||||
|
||||
func callBackExample() {
|
||||
@@ -73,118 +246,147 @@ func callBackExample() {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func sendToInflux(data string) {
|
||||
|
||||
fields := strings.Split(data, ",")
|
||||
|
||||
host := fields[0]
|
||||
token := fields[1]
|
||||
org := fields[2]
|
||||
bucket := fields[3]
|
||||
profile := fields[4]
|
||||
locality := fields[5]
|
||||
metric := fields[6]
|
||||
value := fields[7]
|
||||
|
||||
int_value, err := strconv.Atoi(value)
|
||||
client := influxdb2.NewClient(host, token)
|
||||
writeAPI := client.WriteAPI(org, bucket)
|
||||
|
||||
p := influxdb2.NewPoint(metric,
|
||||
map[string]string{"profile": profile, "locality": locality},
|
||||
map[string]interface{}{"count": int_value},
|
||||
time.Now())
|
||||
|
||||
// write point asynchronously
|
||||
writeAPI.WritePoint(p)
|
||||
|
||||
// Flush writes
|
||||
writeAPI.Flush()
|
||||
|
||||
defer client.Close()
|
||||
|
||||
f, err := os.OpenFile("a3metrics.log",
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
//logger := log.New(f, "", log.LstdFlags)
|
||||
//logger.Println(err)
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
func sendToInflux(data string) {
|
||||
|
||||
fields := strings.Split(data, ",")
|
||||
|
||||
host := fields[0]
|
||||
token := fields[1]
|
||||
org := fields[2]
|
||||
bucket := fields[3]
|
||||
profile := fields[4]
|
||||
locality := fields[5]
|
||||
metric := fields[6]
|
||||
value := fields[7]
|
||||
|
||||
|
||||
client := influxdb2.NewClient(host, token)
|
||||
writeAPI := client.WriteAPI(org, bucket)
|
||||
int_value, err := strconv.Atoi(value)
|
||||
|
||||
|
||||
|
||||
p := influxdb2.NewPoint(metric,
|
||||
map[string]string{"profile": profile, "locality": locality},
|
||||
map[string]interface{}{"count": int_value},
|
||||
time.Now())
|
||||
|
||||
// write point asynchronously
|
||||
writeAPI.WritePoint(p)
|
||||
|
||||
|
||||
|
||||
// Flush writes
|
||||
writeAPI.Flush()
|
||||
|
||||
defer client.Close()
|
||||
|
||||
f, err := os.OpenFile("a3metrics.log",
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
//logger := log.New(f, "", log.LstdFlags)
|
||||
//logger.Println(err)
|
||||
|
||||
func getUnixTimeNano() int64 {
|
||||
// get the current unix timestamp in nanoseconds
|
||||
return time.Now().UnixNano()
|
||||
}
|
||||
|
||||
func trimQuotes(s string) string {
|
||||
// trim the start and end quotes from a string
|
||||
return strings.Trim(s, `"`)
|
||||
}
|
||||
|
||||
func fixEscapeQuotes(s string) string {
|
||||
// fix the escape quotes in a string
|
||||
return strings.Replace(s, `""`, `"`, -1)
|
||||
}
|
||||
|
||||
func sendToInflux(a3DataRaw *[]string) string {
|
||||
|
||||
// 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")
|
||||
defer C.free(unsafe.Pointer(statusName))
|
||||
statusFunction := C.CString(functionName)
|
||||
defer C.free(unsafe.Pointer(statusFunction))
|
||||
statusParam := C.CString(data)
|
||||
defer C.free(unsafe.Pointer(statusParam))
|
||||
runExtensionCallback(statusName, statusFunction, statusParam)
|
||||
|
||||
log.Println(data)
|
||||
}
|
||||
|
||||
//export goRVExtension
|
||||
func goRVExtension(output *C.char, outputsize C.size_t, input *C.char) {
|
||||
// Return by default through ExtensionCallback arma handler the result
|
||||
if extensionCallbackFnc != nil {
|
||||
go callBackExample()
|
||||
} else {
|
||||
// Return a result through callextension Arma call
|
||||
temp := fmt.Sprintf("Rangermetrics: %s", C.GoString(input))
|
||||
result := C.CString(temp)
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
|
||||
var temp string
|
||||
|
||||
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 := 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,
|
||||
)
|
||||
}
|
||||
|
||||
go sendToInflux(C.GoString(input))
|
||||
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
case "connectToInflux":
|
||||
logLine("goRVExtension", fmt.Sprintf(`["Input: %s", "INFO"]`, C.GoString(input)))
|
||||
result := connectToInflux()
|
||||
temp = fmt.Sprintf(`["%s", "INFO"]`, result)
|
||||
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", "ERR"]`, C.GoString(input))
|
||||
}
|
||||
|
||||
result := C.CString(temp)
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
// return
|
||||
}
|
||||
|
||||
//export goRVExtensionRegisterCallback
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extensionCallback.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
|
||||
)
|
||||
|
||||
var extensionCallbackFnc C.extensionCallback
|
||||
|
||||
func runExtensionCallback(name *C.char, function *C.char, data *C.char) C.int {
|
||||
return C.runExtensionCallback(extensionCallbackFnc, name, function, data)
|
||||
}
|
||||
|
||||
//export goRVExtensionVersion
|
||||
func goRVExtensionVersion(output *C.char, outputsize C.size_t) {
|
||||
result := C.CString("Version 1.2.3")
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
}
|
||||
|
||||
//export goRVExtensionArgs
|
||||
func goRVExtensionArgs(output *C.char, outputsize C.size_t, input *C.char, argv **C.char, argc C.int) int {
|
||||
var offset = unsafe.Sizeof(uintptr(0))
|
||||
var out []string
|
||||
for index := C.int(0); index < argc; index++ {
|
||||
out = append(out, C.GoString(*argv))
|
||||
argv = (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + offset))
|
||||
}
|
||||
temp := fmt.Sprintf("Function: %s nb params: %d params: %s!", C.GoString(input), argc, out)
|
||||
|
||||
// Return a result to Arma
|
||||
result := C.CString(temp)
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
return 1
|
||||
}
|
||||
|
||||
func callBackExample() {
|
||||
name := C.CString("arma")
|
||||
defer C.free(unsafe.Pointer(name))
|
||||
function := C.CString("funcToExecute")
|
||||
defer C.free(unsafe.Pointer(function))
|
||||
// Make a callback to Arma
|
||||
for i := 0; i < 3; i++ {
|
||||
time.Sleep(2 * time.Second)
|
||||
param := C.CString(fmt.Sprintf("Loop: %d", i))
|
||||
defer C.free(unsafe.Pointer(param))
|
||||
runExtensionCallback(name, function, param)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func sendToInflux(data string) {
|
||||
|
||||
fields := strings.Split(data, ",")
|
||||
|
||||
host := fields[0]
|
||||
token := fields[1]
|
||||
org := fields[2]
|
||||
bucket := fields[3]
|
||||
profile := fields[4]
|
||||
locality := fields[5]
|
||||
metric := fields[6]
|
||||
value := fields[7]
|
||||
|
||||
int_value, err := strconv.Atoi(value)
|
||||
client := influxdb2.NewClient(host, token)
|
||||
writeAPI := client.WriteAPI(org, bucket)
|
||||
|
||||
p := influxdb2.NewPoint(metric,
|
||||
map[string]string{"profile": profile, "locality": locality},
|
||||
map[string]interface{}{"count": int_value},
|
||||
time.Now())
|
||||
|
||||
// write point asynchronously
|
||||
writeAPI.WritePoint(p)
|
||||
|
||||
// Flush writes
|
||||
writeAPI.Flush()
|
||||
|
||||
defer client.Close()
|
||||
|
||||
f, err := os.OpenFile("a3metrics.log",
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
//logger := log.New(f, "", log.LstdFlags)
|
||||
//logger.Println(err)
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
func sendToInflux(data string) {
|
||||
|
||||
fields := strings.Split(data, ",")
|
||||
|
||||
host := fields[0]
|
||||
token := fields[1]
|
||||
org := fields[2]
|
||||
bucket := fields[3]
|
||||
profile := fields[4]
|
||||
locality := fields[5]
|
||||
metric := fields[6]
|
||||
value := fields[7]
|
||||
|
||||
|
||||
int_value, err := strconv.Atoi(value)
|
||||
client := influxdb2.NewClient(host, token)
|
||||
writeAPI := client.WriteAPI(org, bucket)
|
||||
|
||||
p := influxdb2.NewPoint(metric,
|
||||
map[string]string{"profile": profile, "locality": locality},
|
||||
map[string]interface{}{"count": int_value},
|
||||
time.Now())
|
||||
|
||||
// write point asynchronously
|
||||
writeAPI.WritePoint(p)
|
||||
|
||||
// Flush writes
|
||||
writeAPI.Flush()
|
||||
|
||||
defer client.Close()
|
||||
|
||||
f, err := os.OpenFile("a3metrics.log",
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
//logger := log.New(f, "", log.LstdFlags)
|
||||
//logger.Println(err)
|
||||
|
||||
}
|
||||
|
||||
|
||||
//export goRVExtension
|
||||
func goRVExtension(output *C.char, outputsize C.size_t, input *C.char) {
|
||||
// Return by default through ExtensionCallback arma handler the result
|
||||
if extensionCallbackFnc != nil {
|
||||
go callBackExample()
|
||||
} else {
|
||||
// Return a result through callextension Arma call
|
||||
temp := fmt.Sprintf("Rangermetrics: %s", C.GoString(input))
|
||||
result := C.CString(temp)
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
|
||||
go sendToInflux(C.GoString(input))
|
||||
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
}
|
||||
}
|
||||
|
||||
//export goRVExtensionRegisterCallback
|
||||
func goRVExtensionRegisterCallback(fnc C.extensionCallback) {
|
||||
extensionCallbackFnc = fnc
|
||||
}
|
||||
|
||||
func main() {}
|
||||
@@ -1,195 +0,0 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extensionCallback.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
|
||||
)
|
||||
|
||||
var extensionCallbackFnc C.extensionCallback
|
||||
|
||||
func runExtensionCallback(name *C.char, function *C.char, data *C.char) C.int {
|
||||
return C.runExtensionCallback(extensionCallbackFnc, name, function, data)
|
||||
}
|
||||
|
||||
//export goRVExtensionVersion
|
||||
func goRVExtensionVersion(output *C.char, outputsize C.size_t) {
|
||||
result := C.CString("Version 1.2.3")
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
}
|
||||
|
||||
//export goRVExtensionArgs
|
||||
func goRVExtensionArgs(output *C.char, outputsize C.size_t, input *C.char, argv **C.char, argc C.int) int {
|
||||
var offset = unsafe.Sizeof(uintptr(0))
|
||||
var out []string
|
||||
for index := C.int(0); index < argc; index++ {
|
||||
out = append(out, C.GoString(*argv))
|
||||
argv = (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + offset))
|
||||
}
|
||||
temp := fmt.Sprintf("Function: %s nb params: %d params: %s!", C.GoString(input), argc, out)
|
||||
|
||||
// Return a result to Arma
|
||||
result := C.CString(temp)
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
return 1
|
||||
}
|
||||
|
||||
func callBackExample() {
|
||||
name := C.CString("arma")
|
||||
defer C.free(unsafe.Pointer(name))
|
||||
function := C.CString("funcToExecute")
|
||||
defer C.free(unsafe.Pointer(function))
|
||||
// Make a callback to Arma
|
||||
for i := 0; i < 3; i++ {
|
||||
time.Sleep(2 * time.Second)
|
||||
param := C.CString(fmt.Sprintf("Loop: %d", i))
|
||||
defer C.free(unsafe.Pointer(param))
|
||||
runExtensionCallback(name, function, param)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func sendToInflux(data string) {
|
||||
|
||||
fields := strings.Split(data, ",")
|
||||
|
||||
host := fields[0]
|
||||
token := fields[1]
|
||||
org := fields[2]
|
||||
bucket := fields[3]
|
||||
profile := fields[4]
|
||||
locality := fields[5]
|
||||
metric := fields[6]
|
||||
value := fields[7]
|
||||
|
||||
int_value, err := strconv.Atoi(value)
|
||||
client := influxdb2.NewClient(host, token)
|
||||
writeAPI := client.WriteAPI(org, bucket)
|
||||
|
||||
p := influxdb2.NewPoint(metric,
|
||||
map[string]string{"profile": profile, "locality": locality},
|
||||
map[string]interface{}{"count": int_value},
|
||||
time.Now())
|
||||
|
||||
// write point asynchronously
|
||||
writeAPI.WritePoint(p)
|
||||
|
||||
// Flush writes
|
||||
writeAPI.Flush()
|
||||
|
||||
defer client.Close()
|
||||
|
||||
f, err := os.OpenFile("a3metrics.log",
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
//logger := log.New(f, "", log.LstdFlags)
|
||||
//logger.Println(err)
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
func sendToInflux(data string) {
|
||||
|
||||
fields := strings.Split(data, ",")
|
||||
|
||||
host := fields[0]
|
||||
token := fields[1]
|
||||
org := fields[2]
|
||||
bucket := fields[3]
|
||||
profile := fields[4]
|
||||
locality := fields[5]
|
||||
metric := fields[6]
|
||||
value := fields[7]
|
||||
|
||||
|
||||
client := influxdb2.NewClient(host, token)
|
||||
writeAPI := client.WriteAPI(org, bucket)
|
||||
// int_value, err := strconv.Atoi(value)
|
||||
|
||||
|
||||
|
||||
p := influxdb2.NewPoint(metric,
|
||||
map[string]string{"profile": profile, "locality": locality},
|
||||
map[string]interface{}{"count": int_value},
|
||||
time.Now())
|
||||
|
||||
// write point asynchronously
|
||||
writeAPI.WritePoint(p)
|
||||
|
||||
|
||||
|
||||
// Flush writes
|
||||
writeAPI.Flush()
|
||||
|
||||
defer client.Close()
|
||||
|
||||
f, err := os.OpenFile("a3metrics.log",
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
//logger := log.New(f, "", log.LstdFlags)
|
||||
//logger.Println(err)
|
||||
|
||||
}
|
||||
|
||||
|
||||
//export goRVExtension
|
||||
func goRVExtension(output *C.char, outputsize C.size_t, input *C.char) {
|
||||
// Return by default through ExtensionCallback arma handler the result
|
||||
if extensionCallbackFnc != nil {
|
||||
go callBackExample()
|
||||
} else {
|
||||
// Return a result through callextension Arma call
|
||||
temp := fmt.Sprintf("Rangermetrics: %s", C.GoString(input))
|
||||
result := C.CString(temp)
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
|
||||
go sendToInflux(C.GoString(input))
|
||||
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
}
|
||||
}
|
||||
|
||||
//export goRVExtensionRegisterCallback
|
||||
func goRVExtensionRegisterCallback(fnc C.extensionCallback) {
|
||||
extensionCallbackFnc = fnc
|
||||
}
|
||||
|
||||
func main() {}
|
||||
195
armaMission.go
195
armaMission.go
@@ -1,195 +0,0 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extensionCallback.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
|
||||
)
|
||||
|
||||
var extensionCallbackFnc C.extensionCallback
|
||||
|
||||
func runExtensionCallback(name *C.char, function *C.char, data *C.char) C.int {
|
||||
return C.runExtensionCallback(extensionCallbackFnc, name, function, data)
|
||||
}
|
||||
|
||||
//export goRVExtensionVersion
|
||||
func goRVExtensionVersion(output *C.char, outputsize C.size_t) {
|
||||
result := C.CString("Version 1.2.3")
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
}
|
||||
|
||||
//export goRVExtensionArgs
|
||||
func goRVExtensionArgs(output *C.char, outputsize C.size_t, input *C.char, argv **C.char, argc C.int) int {
|
||||
var offset = unsafe.Sizeof(uintptr(0))
|
||||
var out []string
|
||||
for index := C.int(0); index < argc; index++ {
|
||||
out = append(out, C.GoString(*argv))
|
||||
argv = (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + offset))
|
||||
}
|
||||
temp := fmt.Sprintf("Function: %s nb params: %d params: %s!", C.GoString(input), argc, out)
|
||||
|
||||
// Return a result to Arma
|
||||
result := C.CString(temp)
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
return 1
|
||||
}
|
||||
|
||||
func callBackExample() {
|
||||
name := C.CString("arma")
|
||||
defer C.free(unsafe.Pointer(name))
|
||||
function := C.CString("funcToExecute")
|
||||
defer C.free(unsafe.Pointer(function))
|
||||
// Make a callback to Arma
|
||||
for i := 0; i < 3; i++ {
|
||||
time.Sleep(2 * time.Second)
|
||||
param := C.CString(fmt.Sprintf("Loop: %d", i))
|
||||
defer C.free(unsafe.Pointer(param))
|
||||
runExtensionCallback(name, function, param)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func sendToInflux(data string) {
|
||||
|
||||
fields := strings.Split(data, ",")
|
||||
|
||||
host := fields[0]
|
||||
token := fields[1]
|
||||
org := fields[2]
|
||||
bucket := fields[3]
|
||||
profile := fields[4]
|
||||
locality := fields[5]
|
||||
metric := fields[6]
|
||||
value := fields[7]
|
||||
|
||||
int_value, err := strconv.Atoi(value)
|
||||
client := influxdb2.NewClient(host, token)
|
||||
writeAPI := client.WriteAPI(org, bucket)
|
||||
|
||||
p := influxdb2.NewPoint(metric,
|
||||
map[string]string{"profile": profile, "locality": locality},
|
||||
map[string]interface{}{"count": int_value},
|
||||
time.Now())
|
||||
|
||||
// write point asynchronously
|
||||
writeAPI.WritePoint(p)
|
||||
|
||||
// Flush writes
|
||||
writeAPI.Flush()
|
||||
|
||||
defer client.Close()
|
||||
|
||||
f, err := os.OpenFile("a3metrics.log",
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
//logger := log.New(f, "", log.LstdFlags)
|
||||
//logger.Println(err)
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
func sendToInflux(data string) {
|
||||
|
||||
fields := strings.Split(data, ",")
|
||||
|
||||
host := fields[0]
|
||||
token := fields[1]
|
||||
org := fields[2]
|
||||
bucket := fields[3]
|
||||
profile := fields[4]
|
||||
locality := fields[5]
|
||||
metric := fields[6]
|
||||
value := fields[7]
|
||||
|
||||
|
||||
client := influxdb2.NewClient(host, token)
|
||||
writeAPI := client.WriteAPI(org, bucket)
|
||||
// int_value, err := strconv.Atoi(value)
|
||||
|
||||
|
||||
|
||||
p := influxdb2.NewPoint(metric,
|
||||
map[string]string{"profile": profile, "locality": locality},
|
||||
map[string]interface{}{"count": int_value},
|
||||
time.Now())
|
||||
|
||||
// write point asynchronously
|
||||
writeAPI.WritePoint(p)
|
||||
|
||||
|
||||
|
||||
// Flush writes
|
||||
writeAPI.Flush()
|
||||
|
||||
defer client.Close()
|
||||
|
||||
f, err := os.OpenFile("a3metrics.log",
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
//logger := log.New(f, "", log.LstdFlags)
|
||||
//logger.Println(err)
|
||||
|
||||
}
|
||||
|
||||
|
||||
//export goRVExtension
|
||||
func goRVExtension(output *C.char, outputsize C.size_t, input *C.char) {
|
||||
// Return by default through ExtensionCallback arma handler the result
|
||||
if extensionCallbackFnc != nil {
|
||||
go callBackExample()
|
||||
} else {
|
||||
// Return a result through callextension Arma call
|
||||
temp := fmt.Sprintf("Rangermetrics: %s", C.GoString(input))
|
||||
result := C.CString(temp)
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.strlen(result) + 1
|
||||
if size > outputsize {
|
||||
size = outputsize
|
||||
}
|
||||
|
||||
go sendToInflux(C.GoString(input))
|
||||
|
||||
C.memmove(unsafe.Pointer(output), unsafe.Pointer(result), size)
|
||||
}
|
||||
}
|
||||
|
||||
//export goRVExtensionRegisterCallback
|
||||
func goRVExtensionRegisterCallback(fnc C.extensionCallback) {
|
||||
extensionCallbackFnc = fnc
|
||||
}
|
||||
|
||||
func main() {}
|
||||
48
build.txt
Normal file
48
build.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
$ENV:GOARCH = "amd64"
|
||||
$ENV:CGO_ENABLED = 1
|
||||
# # $ENV:CC = "C:`\Program Files (x86)`\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe"
|
||||
go1.16.4 build -o RangerMetrics_x64.dll -buildmode=c-shared .
|
||||
|
||||
# THIS ONE WORKS
|
||||
$ENV:GOARCH = "amd64"
|
||||
$ENV:CGO_ENABLED = 1
|
||||
go1.16.4 build -o RangerMetrics_x64.dll -buildmode=c-shared .
|
||||
|
||||
|
||||
. "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\dumpbin.exe" /exports .\RangerMetrics_x64.dll
|
||||
|
||||
|
||||
go build -buildmode=c-archive basictest.go
|
||||
gcc -shared -W -c -c -c -o basictest_x64.dll RVExtension.c bases -Wl, --subsystem -Wl, windows -Wl, --inable-ctdcall-fixuptes -Wl, --subsystem -Wl, windows -Wl, --enable-stdcall-fixupt.a -Wl, --subsystem -Wl, windows -Wl, --enable-stdcall-fixup
|
||||
|
||||
g++ -o test -l mingw32 RVExtension.c .\RangerMetrics_x64.dll
|
||||
|
||||
|
||||
go build -buildmode=c-archive arma.go
|
||||
gcc -shared -pthread -o RangerMetrics_x64.dll RVExtension.c arma.a -lWinMM -lntdll -lWS2_32
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$ENV:GOARCH = 386
|
||||
$ENV:CGO_ENABLED = 1
|
||||
go build -buildmode=c-archive basictest.go
|
||||
gcc -shared -pthread -o basictest_x64.dll -fPIC RVExtension.c basictest.a
|
||||
|
||||
$ENV:GOARCH = "amd64"
|
||||
$ENV:CGO_ENABLED = 1
|
||||
go build -buildmode=c-archive basictest.go
|
||||
. "C:\TDM-GCC-64-9.2.0\bin\gcc.exe" -shared -pthread -o basictest_x64.dll RVExtension.c basictest.a
|
||||
|
||||
$ENV:GOARCH = 386
|
||||
$ENV:CGO_ENABLED = 1
|
||||
go build -o basictest.dll -buildmode=c-shared .
|
||||
. "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\dumpbin.exe" /exports .\basictest.dll
|
||||
|
||||
$ENV:GOARCH = "amd64"
|
||||
$ENV:CGO_ENABLED = 1
|
||||
$ENV:GOOS = "windows"
|
||||
$ENV:CC = "x86_64-w64-mingw32-gcc"
|
||||
go build -o basictest_x64.dll -buildmode=c-shared .
|
||||
. "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\dumpbin.exe" /exports .\basictest_x64.dll
|
||||
BIN
callExtension.exe
Normal file
BIN
callExtension.exe
Normal file
Binary file not shown.
BIN
callExtension_x64.exe
Normal file
BIN
callExtension_x64.exe
Normal file
Binary file not shown.
@@ -5,6 +5,7 @@
|
||||
typedef int (*extensionCallback)(char const *name, char const *function, char const *data);
|
||||
|
||||
/* https://golang.org/cmd/cgo/#hdr-C_references_to_Go */
|
||||
static inline int runExtensionCallback(extensionCallback fnc, char const *name, char const *function, char const *data) {
|
||||
static inline int runExtensionCallback(extensionCallback fnc, char const *name, char const *function, char const *data)
|
||||
{
|
||||
return fnc(name, function, data);
|
||||
}
|
||||
5
go.sum
5
go.sum
@@ -1,12 +1,9 @@
|
||||
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.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deepmap/oapi-codegen v1.6.0 h1:w/d1ntwh91XI0b/8ja7+u5SvA4IFfM0UNNLmiDR1gg0=
|
||||
github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M=
|
||||
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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/getkin/kin-openapi v0.53.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/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
@@ -14,8 +11,6 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.3.0 h1:4YzLWRsPUoHuQYWDwPoybaJjN01e0/k0AIQO85ymCKI=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.3.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8=
|
||||
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/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
|
||||
|
||||
10
makefile
10
makefile
@@ -1,4 +1,12 @@
|
||||
build:
|
||||
export GOARCH="amd64"
|
||||
export CGO_ENABLED=1
|
||||
go build -o armago.dll -buildmode=c-shared .
|
||||
go build -o RangerMetrics_x64.so -buildmode=c-shared .
|
||||
|
||||
export GOARCH = "386"
|
||||
export CGO_ENABLED = 1
|
||||
go build -o RangerMetrics.dll -buildmode=c-shared .
|
||||
|
||||
export GOARCH = "amd64"
|
||||
export CGO_ENABLED = 1
|
||||
go build -o RangerMetrics_x64.dll -buildmode=c-shared .
|
||||
|
||||
6
settings.json.example
Normal file
6
settings.json.example
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"host" : "http://INFLUX_URL:8086",
|
||||
"token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXX_AUTH_TOKEN_XXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"org" : "ORG_NAME",
|
||||
"bucket" : "BUCKET_NAME",
|
||||
}
|
||||
18
testsqf.sqf
Normal file
18
testsqf.sqf
Normal file
@@ -0,0 +1,18 @@
|
||||
freeExtension "RangerMetrics";
|
||||
// sleep 0.5;
|
||||
"RangerMetrics" callExtension "loadSettings";
|
||||
|
||||
// sleep 3;
|
||||
// "RangerMetrics" callExtension "version";
|
||||
// sleep 3;
|
||||
// "RangerMetrics" callExtension "connectToInflux";
|
||||
// // sleep 3;
|
||||
// // sleep 100;
|
||||
// "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"]];
|
||||
|
||||
sleep 30;
|
||||
// freeExtension "RangerMetrics";
|
||||
|
||||
|
||||
|
||||
exit;
|
||||
Reference in New Issue
Block a user