Path discovery is ported directly from Discord's C++ example, Windows has a crazy looking socket path that needs special syscall magic to dial, so we'll put that off for the time being. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
92 lines
1.8 KiB
Go
92 lines
1.8 KiB
Go
package rpcfetch
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"net"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
type Client struct {
|
|
id string
|
|
|
|
dialed bool
|
|
active bool
|
|
net.Conn
|
|
}
|
|
|
|
// Raw wraps around the Raw method to provide generic json parsing
|
|
func Raw[T any](d *Client, opcode uint32, payload any) (uint32, T, error) {
|
|
var p T
|
|
|
|
opcodeResp, payloadResp, err := d.Raw(opcode, payload)
|
|
if err != nil {
|
|
return opcodeResp, p, err
|
|
}
|
|
|
|
return opcodeResp, p, json.Unmarshal(payloadResp, &p)
|
|
}
|
|
|
|
// Raw writes a raw payload to Discord and returns the response opcode and payload
|
|
func (d *Client) Raw(opcode uint32, payload any) (uint32, []byte, error) {
|
|
if err := binary.Write(d.Conn, binary.LittleEndian, opcode); err != nil {
|
|
return 0, nil, err
|
|
}
|
|
|
|
if p, err := json.Marshal(payload); err != nil {
|
|
return 0, nil, err
|
|
} else {
|
|
if err = binary.Write(d.Conn, binary.LittleEndian, uint32(len(p))); err != nil {
|
|
return 0, nil, err
|
|
}
|
|
|
|
if _, err = d.Conn.Write(p); err != nil {
|
|
return 0, nil, err
|
|
}
|
|
}
|
|
|
|
var (
|
|
opcodeResp uint32
|
|
lengthResp uint32
|
|
)
|
|
|
|
if err := binary.Read(d.Conn, binary.LittleEndian, &opcodeResp); err != nil {
|
|
return 0, nil, err
|
|
}
|
|
|
|
if err := binary.Read(d.Conn, binary.LittleEndian, &lengthResp); err != nil {
|
|
return 0, nil, err
|
|
}
|
|
|
|
payloadResp := make([]byte, lengthResp)
|
|
_, err := d.Read(payloadResp)
|
|
return opcodeResp, payloadResp, err
|
|
}
|
|
|
|
// New sets up and returns the reference to a new Client
|
|
func New(id string) *Client {
|
|
d := &Client{
|
|
id: id,
|
|
}
|
|
|
|
return d
|
|
}
|
|
|
|
func sockPath() string {
|
|
snap := "/run/user/" + strconv.Itoa(os.Getuid()) + "/snap.discord"
|
|
|
|
if _, err := os.Stat(snap); err == nil {
|
|
return snap
|
|
}
|
|
|
|
for _, env := range []string{"XDG_RUNTIME_DIR", "TMPDIR", "TMP", "TEMP"} {
|
|
if val, ok := os.LookupEnv(env); ok {
|
|
return val
|
|
}
|
|
}
|
|
|
|
// fallback
|
|
return "/tmp"
|
|
}
|