Merge from Jack
This commit is contained in:
commit
a573a55238
|
@ -0,0 +1,9 @@
|
|||
# A3Web
|
||||
|
||||
Arma 3 Realtime Map
|
||||
|
||||
## To build extension
|
||||
|
||||
```
|
||||
GOARCH=386 CGO_ENABLED=1 go build -o liba3web.so -buildmode=c-shared .
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
x\huashui\a3web
|
|
@ -0,0 +1,27 @@
|
|||
class CfgPatches
|
||||
{
|
||||
class a3web
|
||||
{
|
||||
name = "Arma 3 Realtime Map";
|
||||
author = "jack77213";
|
||||
url = "https://arma.huashui.cf";
|
||||
|
||||
requiredVersion = 1.92;
|
||||
requiredAddons[] = {"A3_Functions_F"};
|
||||
units[] = {};
|
||||
weapons[] = {};
|
||||
};
|
||||
};
|
||||
|
||||
class CfgFunctions
|
||||
{
|
||||
class huashui
|
||||
{
|
||||
class a3web
|
||||
{
|
||||
file = "x\huashui\a3web";
|
||||
class a3web { postInit=1; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
[] spawn {
|
||||
//if (!hasInterface) exitWith {};
|
||||
if (!isServer) exitWith {};
|
||||
//if (!isDedicated) exitWith {};
|
||||
|
||||
addMissionEventHandler ["ExtensionCallback", {
|
||||
params ["_name", "_function", "_data"];
|
||||
if (_name isEqualTo "a3web") then
|
||||
{
|
||||
diag_log format ["ExtensionCallback %1, %2, %3", _name, _function, _data];
|
||||
};
|
||||
}];
|
||||
|
||||
waitUntil {time > 0};
|
||||
|
||||
a3web_interval = 1;
|
||||
|
||||
while {true} do {
|
||||
sleep a3web_interval;
|
||||
private _units = allUnits apply {
|
||||
[netid _x, isPlayer _x, name _x, str (side _x), getPos _x];
|
||||
};
|
||||
"liba3web" callExtension ["http:post:/units-info", [_units]];
|
||||
};
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
module gitea.hijack.moe/huashui/a3web/extension
|
||||
|
||||
go 1.13
|
|
@ -0,0 +1,84 @@
|
|||
package main
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef int(*callbackProc)(char const *name, char const *function, char const *data);
|
||||
|
||||
static inline int bridge_cb(callbackProc cb, char const *name, char const *function, char const *data) {
|
||||
return cb(name, function, data);
|
||||
}
|
||||
|
||||
static inline uint min(uint a, uint b) { return a < b ? a : b; }
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"unsafe"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var cb C.callbackProc
|
||||
var name = C.CString("a3web")
|
||||
var serverURL = "https://localhost"
|
||||
|
||||
// RVExtensionRegisterCallback on extension load
|
||||
//export RVExtensionRegisterCallback
|
||||
func RVExtensionRegisterCallback(cbptr unsafe.Pointer) {
|
||||
cb = C.callbackProc(cbptr)
|
||||
|
||||
log.Println("Calling callback function ……")
|
||||
function := C.CString("registered")
|
||||
defer C.free(unsafe.Pointer(function))
|
||||
C.bridge_cb(cb, name, function, function)
|
||||
}
|
||||
|
||||
// RVExtensionVersion on extension load
|
||||
//export RVExtensionVersion
|
||||
func RVExtensionVersion(output *C.char, outputsize C.size_t) {
|
||||
version := C.CString("Version 0.1")
|
||||
defer C.free(unsafe.Pointer(version))
|
||||
var size = C.min(C.strlen(version)+1, outputsize-1)
|
||||
C.strncpy(output, version, size)
|
||||
}
|
||||
|
||||
// RVExtensionArgs STRING callExtension ARRAY
|
||||
//export RVExtensionArgs
|
||||
func RVExtensionArgs(output *C.char, outputsize C.size_t, function *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))
|
||||
}
|
||||
|
||||
go handleArgs(C.GoString(function), argc, out)
|
||||
}
|
||||
|
||||
// RVExtension STRING callExtension STRING
|
||||
//export RVExtension
|
||||
func RVExtension(output *C.char, outputsize C.size_t, function *C.char) {
|
||||
result := C.CString(fmt.Sprintf("Hello, %s!", C.GoString(function)))
|
||||
defer C.free(unsafe.Pointer(result))
|
||||
var size = C.min(C.strlen(result)+1, outputsize-1)
|
||||
C.strncpy(output, result, size)
|
||||
}
|
||||
|
||||
func main() {}
|
||||
|
||||
func handleArgs(function string, argc C.int, argv []string) {
|
||||
fns := strings.Split(strings.ToLower(function), ":")
|
||||
if len(fns) == 3 && fns[0] == "http" && fns[1] == "post" {
|
||||
resp, err := http.Post(serverURL + fns[2], "", strings.NewReader(argv[0]))
|
||||
if err != nil {
|
||||
log.Printf("Error Sending HTTP Request: %s", err)
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
module gitea.hijack.moe/huashui/a3web/server
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2
|
||||
github.com/gin-gonic/gin v1.5.0
|
||||
)
|
|
@ -0,0 +1,38 @@
|
|||
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/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2 h1:xLG16iua01X7Gzms9045s2Y2niNpvSY/Zb1oBwgNYZY=
|
||||
github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2/go.mod h1:VhW/Ch/3FhimwZb8Oj+qJmdMmoB8r7lmJ5auRjm50oQ=
|
||||
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
|
||||
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
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/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
@ -0,0 +1,94 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/gin-contrib/static"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var (
|
||||
unitsInfo = make([]unitInfo, 0)
|
||||
unitsInfoMutex = sync.RWMutex{}
|
||||
)
|
||||
|
||||
type position []float64
|
||||
|
||||
type unitInfo struct {
|
||||
NetID string `json:"netid"`
|
||||
IsPlayer bool `json:"isplayer"`
|
||||
ProfileName string `json:"profilename"`
|
||||
Side string `json:"side"`
|
||||
Position position `json:"position"`
|
||||
}
|
||||
|
||||
func (u *unitInfo) UnmarshalJSON(buf []byte) error {
|
||||
tmp := []interface{}{
|
||||
&u.NetID,
|
||||
&u.IsPlayer,
|
||||
&u.ProfileName,
|
||||
&u.Side,
|
||||
&u.Position,
|
||||
}
|
||||
wantLen := len(tmp)
|
||||
if err := json.Unmarshal(buf, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
if g, e := len(tmp), wantLen; g != e {
|
||||
return fmt.Errorf("wrong number of fields in Notification: %d != %d", g, e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
listenAddress := os.Getenv("LISTEN_ADDR")
|
||||
if listenAddress == "" {
|
||||
listenAddress = ":5000"
|
||||
}
|
||||
|
||||
router := gin.Default()
|
||||
router.Use(static.Serve("/", static.LocalFile("../ui/public", false)))
|
||||
router.Use(static.Serve("/maps", static.LocalFile("../maps", false)))
|
||||
|
||||
router.GET("/ping", func(c *gin.Context) {
|
||||
c.String(http.StatusOK, "pong")
|
||||
})
|
||||
|
||||
router.POST("/ping", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "pong",
|
||||
})
|
||||
})
|
||||
|
||||
router.POST("/units-info", updateUnitsInfo)
|
||||
router.GET("/units-info", getUnitsInfo)
|
||||
|
||||
router.Run(listenAddress)
|
||||
}
|
||||
|
||||
func updateUnitsInfo(c *gin.Context) {
|
||||
ups := make([]unitInfo, 0)
|
||||
err := c.ShouldBindJSON(&ups)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
c.JSON(http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
unitsInfoMutex.Lock()
|
||||
defer unitsInfoMutex.Unlock()
|
||||
unitsInfo = ups
|
||||
|
||||
c.JSON(http.StatusOK, nil)
|
||||
}
|
||||
|
||||
func getUnitsInfo(c *gin.Context) {
|
||||
unitsInfoMutex.RLock()
|
||||
defer unitsInfoMutex.RUnlock()
|
||||
c.JSON(http.StatusOK, unitsInfo)
|
||||
}
|
Loading…
Reference in New Issue