pygomx/libmxclient/mxclientlib.go

311 lines
7.6 KiB
Go
Raw Normal View History

2026-01-13 13:11:02 +01:00
// Copyright (C) 2026 saces@c-base.org
// SPDX-License-Identifier: AGPL-3.0-only
2026-01-09 18:52:31 +01:00
package main
2026-01-12 17:39:34 +01:00
import (
2026-01-31 08:13:53 +01:00
"context"
"encoding/json"
2026-02-06 16:10:58 +01:00
"errors"
2026-01-31 08:13:53 +01:00
"fmt"
"mxclientlib/mxapi"
"mxclientlib/mxclient"
2026-01-20 06:48:27 +01:00
"mxclientlib/mxutils"
2026-01-18 23:35:07 +01:00
"unsafe"
2026-01-31 08:13:53 +01:00
"maunium.net/go/mautrix/id"
2026-01-12 17:39:34 +01:00
)
2026-01-18 23:35:07 +01:00
/*
#include <stdlib.h>
typedef void (*on_event_handler_ptr) (char*, void*);
typedef void (*on_message_handler_ptr) (char*, void*);
2026-01-31 08:13:53 +01:00
static inline void call_c_on_event_handler(on_event_handler_ptr ptr, char* jsonStr, void* pobj) {
(ptr)(jsonStr, pobj);
2026-01-31 08:13:53 +01:00
}
static inline void call_c_on_message_handler(on_message_handler_ptr ptr, char* jsonStr, void* pobj) {
(ptr)(jsonStr, pobj);
2026-01-31 08:13:53 +01:00
}
2026-01-18 23:35:07 +01:00
*/
2026-01-09 18:52:31 +01:00
import "C"
2026-02-06 16:10:58 +01:00
var apiCanceled = errors.New("canceled by api call")
2026-01-31 08:13:53 +01:00
/*
matrix client with c callback
*/
type CBClient struct {
*mxclient.MXClient
on_event_handler C.on_event_handler_ptr
on_event_handler_pobj unsafe.Pointer
on_message_handler C.on_message_handler_ptr
on_message_handler_pobj unsafe.Pointer
2026-02-06 16:10:58 +01:00
syncCancelFunc context.CancelCauseFunc
2026-01-31 08:13:53 +01:00
}
func (cli *CBClient) OnEvent(s string) {
cStr := C.CString(s)
defer C.free(unsafe.Pointer(cStr))
C.call_c_on_event_handler(cli.on_event_handler, cStr, cli.on_event_handler_pobj)
2026-01-31 08:13:53 +01:00
}
func (cli *CBClient) OnMessage(s string) {
cStr := C.CString(s)
defer C.free(unsafe.Pointer(cStr))
C.call_c_on_message_handler(cli.on_message_handler, cStr, cli.on_message_handler_pobj)
2026-01-31 08:13:53 +01:00
}
func (cli *CBClient) Set_on_event_handler(fn C.on_event_handler_ptr, pobj unsafe.Pointer) {
2026-01-31 08:13:53 +01:00
cli.on_event_handler = fn
cli.on_event_handler_pobj = pobj
2026-01-31 08:13:53 +01:00
}
func (cli *CBClient) Set_on_message_handler(fn C.on_message_handler_ptr, pobj unsafe.Pointer) {
2026-01-31 08:13:53 +01:00
cli.on_message_handler = fn
cli.on_message_handler_pobj = pobj
2026-01-31 08:13:53 +01:00
}
// NewCClient creates a new Matrix Client ready for syncing
func NewCBClient(homeserverURL string, userID id.UserID, accessToken string) (*CBClient, error) {
client, err := mxclient.NewMXClient(homeserverURL, userID, accessToken)
if err != nil {
return nil, err
}
2026-02-06 05:41:47 +01:00
return &CBClient{client, nil, nil, nil, nil, nil}, nil
2026-01-31 08:13:53 +01:00
}
/*
account/client management
*/
var cclients []*CBClient
func getClient(id int) (*CBClient, error) {
if id < 0 || id >= len(cclients) {
return nil, fmt.Errorf("index out of bounds: '%d'", id)
}
res := cclients[id]
return res, nil
}
/*
helperse
*/
2026-01-18 23:35:07 +01:00
//export FreeCString
func FreeCString(s *C.char) {
C.free(unsafe.Pointer(s))
}
2026-01-13 13:11:02 +01:00
/*
cli tools
*/
2026-01-31 08:13:53 +01:00
2026-01-13 13:11:02 +01:00
//export cli_discoverhs
func cli_discoverhs(id *C.char) *C.char {
2026-01-12 17:39:34 +01:00
mxid := C.GoString(id)
2026-01-20 06:48:27 +01:00
result := mxutils.DiscoverHS(mxid)
2026-01-12 17:39:34 +01:00
return C.CString(result)
}
2026-01-13 13:11:02 +01:00
//export cli_mkmxtoken
func cli_mkmxtoken(id *C.char, pw *C.char) *C.char {
mxid := C.GoString(id)
mxpw := C.GoString(pw)
2026-01-20 06:48:27 +01:00
result := mxutils.MkToken(mxid, mxpw)
2026-01-09 18:52:31 +01:00
return C.CString(result)
}
2026-01-13 13:11:02 +01:00
//export cli_whoami
func cli_whoami(hs *C.char, tk *C.char) *C.char {
_hs := C.GoString(hs)
_tk := C.GoString(tk)
2026-01-20 06:48:27 +01:00
result := mxutils.Whoami(_hs, _tk)
2026-01-13 13:11:02 +01:00
return C.CString(result)
}
//export cli_accountinfo
func cli_accountinfo(hs *C.char, tk *C.char) *C.char {
_hs := C.GoString(hs)
_tk := C.GoString(tk)
2026-01-20 06:48:27 +01:00
result := mxutils.AccountInfo(_hs, _tk)
2026-01-13 13:11:02 +01:00
return C.CString(result)
}
//export cli_clearaccount
func cli_clearaccount(hs *C.char, tk *C.char) *C.char {
_hs := C.GoString(hs)
_tk := C.GoString(tk)
2026-01-20 06:48:27 +01:00
result := mxutils.ClearAccount(_hs, _tk)
2026-01-13 13:11:02 +01:00
return C.CString(result)
}
//export cli_serverinfo
func cli_serverinfo(url *C.char) *C.char {
_url := C.GoString(url)
2026-01-20 06:48:27 +01:00
result := mxutils.ServerInfo(_url)
2026-01-13 13:11:02 +01:00
return C.CString(result)
}
/*
2026-01-31 08:13:53 +01:00
high level api, supports multiple clients
the same handler can be attached to multiple clients
2026-01-13 13:11:02 +01:00
*/
2026-01-31 08:13:53 +01:00
//export apiv0_initialize
func apiv0_initialize() C.int {
2026-01-13 13:11:02 +01:00
return 0
}
2026-01-31 08:13:53 +01:00
//export apiv0_deinitialize
func apiv0_deinitialize() C.int {
return 0
}
//export apiv0_discover
func apiv0_discover(mxid *C.char) *C.char {
result, err := mxapi.Discover(C.GoString(mxid))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
return C.CString(result)
}
//export apiv0_login
func apiv0_login(data *C.char) *C.char {
result, err := mxapi.Login(C.GoString(data))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
return C.CString(result)
}
//export apiv0_createclient
func apiv0_createclient(storage_path *C.char, url *C.char, userID *C.char, accessToken *C.char) *C.char {
mxclient, err := mxclient.CreateClient(C.GoString(storage_path), C.GoString(url), C.GoString(userID), C.GoString(accessToken))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
2026-02-06 05:41:47 +01:00
client := &CBClient{mxclient, nil, nil, nil, nil, nil}
2026-01-31 08:13:53 +01:00
cclients = append(cclients, client)
return C.CString(fmt.Sprintf("{ \"id:\"SUCESS. ID=%d\n", len(cclients)))
}
//export apiv0_createclient_pass
func apiv0_createclient_pass(mxpassfile_path *C.char, storage_path *C.char, url *C.char, localpart *C.char, domain *C.char) *C.char {
mxclient, err := mxclient.CreateClientPass(C.GoString(mxpassfile_path), C.GoString(storage_path), C.GoString(url), C.GoString(localpart), C.GoString(domain))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
2026-02-06 05:41:47 +01:00
client := &CBClient{mxclient, nil, nil, nil, nil, nil}
2026-01-31 08:13:53 +01:00
mxclient.OnEvent = client.OnEvent
mxclient.OnMessage = client.OnMessage
cclients = append(cclients, client)
out, err := json.Marshal(map[string]int{"id": len(cclients) - 1})
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
s := string(out)
return C.CString(s)
}
//export apiv0_set_on_event_handler
func apiv0_set_on_event_handler(cid C.int, fn C.on_event_handler_ptr, pobj unsafe.Pointer) *C.char {
2026-01-31 08:13:53 +01:00
cli, err := getClient(int(cid))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
cli.Set_on_event_handler(fn, pobj)
2026-01-31 08:13:53 +01:00
return C.CString("SUCCESS.")
}
//export apiv0_set_on_message_handler
func apiv0_set_on_message_handler(cid C.int, fn C.on_message_handler_ptr, pobj unsafe.Pointer) *C.char {
2026-01-31 08:13:53 +01:00
cli, err := getClient(int(cid))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
cli.Set_on_message_handler(fn, pobj)
2026-01-31 08:13:53 +01:00
return C.CString("SUCCESS.")
}
//export apiv0_startclient
func apiv0_startclient(cid C.int) *C.char {
cli, err := getClient(int(cid))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
2026-02-06 16:10:58 +01:00
ctx, cancel := context.WithCancelCause(context.Background())
2026-02-06 05:41:47 +01:00
cli.syncCancelFunc = cancel
err = cli.SyncWithContext(ctx)
2026-01-31 08:13:53 +01:00
if err != nil {
2026-02-06 16:10:58 +01:00
if errors.Is(err, context.Canceled) {
cause := context.Cause(ctx)
if errors.Is(cause, apiCanceled) {
return C.CString("SUCCESS.")
} else {
return C.CString(fmt.Sprintf("ERR: %v", cause))
}
}
2026-01-31 08:13:53 +01:00
return C.CString(fmt.Sprintf("ERR: %v", err))
}
return C.CString("SUCCESS.")
}
//export apiv0_stopclient
func apiv0_stopclient(cid C.int) *C.char {
cli, err := getClient(int(cid))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
cli.StopSync()
2026-02-06 16:10:58 +01:00
cli.syncCancelFunc(apiCanceled)
2026-02-06 05:41:47 +01:00
2026-01-31 08:13:53 +01:00
return C.CString("SUCCESS.")
}
//export apiv0_sendmessage
func apiv0_sendmessage(cid C.int, data *C.char) *C.char {
cli, err := getClient(int(cid))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
result, err := cli.SendRoomMessage(context.Background(), C.GoString(data))
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
out, err := json.Marshal(result)
if err != nil {
return C.CString(fmt.Sprintf("ERR: %v", err))
}
s := string(out)
return C.CString(s)
}
//export apiv0_removeclient
func apiv0_removeclient(cid C.int) C.int {
return 0
}
//export apiv0_listclients
func apiv0_listclients() *C.char {
return C.CString("{}")
}
//export apiv0_getoptions
func apiv0_getoptions(cid C.int) *C.char {
return C.CString("{}")
}
//export apiv0_setoptions
func apiv0_setoptions(cid C.int, opts *C.char) C.int {
2026-01-13 13:11:02 +01:00
return 0
}
2026-01-09 18:52:31 +01:00
func main() {}