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" }