Linux can now read from a shared memory map and the sdk can create it
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
// I should rename winutils to something else but what this package does
|
||||
// is interface some windows stuff that we need for the:
|
||||
// - Broadcast Channel
|
||||
// - Valid Data Event windows thing
|
||||
package mmaputils
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Reader interface {
|
||||
io.Reader
|
||||
io.ReaderAt
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
type IRacingWinUtils struct {
|
||||
Utils *utils
|
||||
}
|
||||
|
||||
func Init() (*IRacingWinUtils, error) {
|
||||
u, err := newUtils()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &IRacingWinUtils{u}, nil
|
||||
}
|
||||
|
||||
func (u *IRacingWinUtils) Close() {
|
||||
u.Utils.Close()
|
||||
}
|
||||
|
||||
// OpenWinEvent will open the named windows event
|
||||
func (u *IRacingWinUtils) OpenWinEvent(name string) error {
|
||||
return u.Utils.OpenEvent(name)
|
||||
}
|
||||
|
||||
// OpenBroadcastChannel will open the broadcast channel
|
||||
func (u *IRacingWinUtils) OpenBroadcastChannel(name string) error {
|
||||
return u.Utils.OpenBroadcastChannel(name)
|
||||
}
|
||||
|
||||
// CheckValidDataEvent checks if our windows even is telling us we are good to go
|
||||
func (u *IRacingWinUtils) CheckValidDataEvent(timeout time.Duration) bool {
|
||||
return u.Utils.CheckValidDataEvent(timeout)
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
//go:build (linux && cgo) || (darwin && cgo)
|
||||
|
||||
package mmaputils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/ESilva15/goirsdk/sharedMem"
|
||||
)
|
||||
|
||||
type utils struct {
|
||||
socketPath string
|
||||
listener *net.UnixConn
|
||||
}
|
||||
|
||||
func newUtils() (*utils, error) {
|
||||
return &utils{}, nil
|
||||
}
|
||||
|
||||
func (u *utils) Close() {
|
||||
if u.listener != nil {
|
||||
u.listener.Close()
|
||||
os.Remove(u.socketPath)
|
||||
}
|
||||
}
|
||||
|
||||
// OpenMemMap returns a Reader interface that can be used to read the data
|
||||
// No need to encapsulate it
|
||||
func OpenMemMap(name string, size uint32) (Reader, error) {
|
||||
file, err := sharedMem.Open(name, size)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open `%s` with err: %+v", name, err)
|
||||
}
|
||||
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// OpenEvent creates or connects to a Unix socket for event signaling on Linux
|
||||
func (u *utils) OpenEvent(eventName string) error {
|
||||
u.socketPath = fmt.Sprintf("/tmp/iracing_%s.sock", eventName)
|
||||
_ = os.Remove(u.socketPath)
|
||||
|
||||
addr, err := net.ResolveUnixAddr("unixgram", u.socketPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l, err := net.ListenUnixgram("unixgram", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.listener = l
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *utils) OpenBroadcastChannel(name string) error {
|
||||
// No-op or log stub on Linux
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckValidDataEvent waits for a pulse byte sent over the socket
|
||||
func (u *utils) CheckValidDataEvent(timeout time.Duration) bool {
|
||||
if u.listener == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_ = u.listener.SetReadDeadline(time.Now().Add(timeout))
|
||||
buf := make([]byte, 1)
|
||||
_, err := u.listener.Read(buf)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (u *utils) SendBroadcastMessage(id, p1, p2 uintptr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// package winutils
|
||||
//
|
||||
// import (
|
||||
// "errors"
|
||||
// "sync"
|
||||
// "time"
|
||||
// )
|
||||
//
|
||||
// const (
|
||||
// WAIT_OBJECT_0 = 0
|
||||
// WAIT_TIMEOUT = 258
|
||||
// )
|
||||
//
|
||||
// var (
|
||||
// once sync.Once
|
||||
// ErrUnsupportedOS = errors.New("not found")
|
||||
// )
|
||||
//
|
||||
// type utils struct {
|
||||
// }
|
||||
//
|
||||
// // INITIALIZATION
|
||||
// func newUtils() (*utils, error) {
|
||||
// return nil, ErrUnsupportedOS
|
||||
// }
|
||||
//
|
||||
// func (u *utils) Close() {
|
||||
// }
|
||||
//
|
||||
// // openEvent opens a windows.Handle for a given event
|
||||
// func (u *utils) OpenEvent(eventName string) error {
|
||||
// return ErrUnsupportedOS
|
||||
// }
|
||||
//
|
||||
// // OpenBroadcastChannel opens up a broadcast channel to send commands to iracing
|
||||
// func (u *utils) OpenBroadcastChannel(name string) error {
|
||||
// return ErrUnsupportedOS
|
||||
// }
|
||||
//
|
||||
// // INITIALIZATION
|
||||
//
|
||||
// // openEvent waits for a good response for some given time
|
||||
// func (u *utils) CheckValidDataEvent(timeout time.Duration) bool {
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// // SendBroadcastMessage sends a message trough the broadcast channel
|
||||
// func (u *utils) SendBroadcastMessage(id, p1, p2 uintptr) error {
|
||||
// return ErrUnsupportedOS
|
||||
// }
|
||||
@@ -0,0 +1,131 @@
|
||||
// go:build windows
|
||||
|
||||
package mmaputils
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ESilva15/goirsdk/sharedMem"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
WAIT_OBJECT_0 = 0
|
||||
WAIT_TIMEOUT = 258
|
||||
)
|
||||
|
||||
var once sync.Once
|
||||
|
||||
type utils struct {
|
||||
user32DLL *windows.LazyDLL
|
||||
wEvent windows.Handle
|
||||
wBroadcastChn uintptr
|
||||
}
|
||||
|
||||
// INITIALIZATION
|
||||
func newUtils() (*utils, error) {
|
||||
return &utils{
|
||||
user32DLL: openUser32DLL(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *utils) Close() {
|
||||
closeEvent(&u.wEvent)
|
||||
// Do we need to unload the user32DLL ???
|
||||
// Do we need to close the broadcast channel ???
|
||||
}
|
||||
|
||||
// OpenMemMap returns a Reader interface that can be used to read the data
|
||||
// No need to encapsulate it
|
||||
func OpenMemMap(name string, size uint32) (Reader, error) {
|
||||
file, err := sharedMem.Open("Local\\"+name, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// openEvent opens a windows.Handle for a given event
|
||||
func (u *utils) OpenEvent(eventName string) error {
|
||||
name, err := windows.UTF16PtrFromString(eventName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event, err := windows.OpenEvent(windows.SYNCHRONIZE, false, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.wEvent = event
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadUser32DLL loads the user32.dll which is used to create some processes
|
||||
func openUser32DLL() *windows.LazyDLL {
|
||||
return windows.NewLazyDLL("user32.dll")
|
||||
}
|
||||
|
||||
// OpenBroadcastChannel opens up a broadcast channel to send commands to iracing
|
||||
func (u *utils) OpenBroadcastChannel(name string) error {
|
||||
registerWindowsMessageW := u.user32DLL.NewProc("RegisterWindowMessageW")
|
||||
|
||||
msgPtr, err := windows.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ret, _, err := registerWindowsMessageW.Call(uintptr(unsafe.Pointer(msgPtr)))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
u.wBroadcastChn = ret
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// INITIALIZATION
|
||||
|
||||
// closeEvent closes a given windows.Handle
|
||||
func closeEvent(h *windows.Handle) {
|
||||
windows.CloseHandle(*h)
|
||||
}
|
||||
|
||||
// openEvent waits for a good response for some given time
|
||||
func (u *utils) CheckValidDataEvent(timeout time.Duration) bool {
|
||||
t0 := time.Now().UnixNano()
|
||||
timeoutInt := uint32(timeout / time.Millisecond)
|
||||
|
||||
result, err := windows.WaitForSingleObject(u.wEvent, timeoutInt)
|
||||
if err != nil {
|
||||
remaining := timeoutInt - uint32((time.Now().UnixNano()-t0)/1000000)
|
||||
if remaining > 0 {
|
||||
time.Sleep(time.Duration(remaining) * time.Millisecond)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Check the result of the wait
|
||||
if result == WAIT_OBJECT_0 {
|
||||
return true
|
||||
} else if result == WAIT_TIMEOUT {
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SendBroadcastMessage sends a message trough the broadcast channel
|
||||
func (u *utils) SendBroadcastMessage(id, p1, p2 uintptr) error {
|
||||
sendMsg := u.user32DLL.NewProc("SendNotifyMessageW")
|
||||
ret, _, err := sendMsg.Call(0xffff, id, p1, p2)
|
||||
|
||||
if ret == 1 {
|
||||
return nil
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user