Help us shape the future of Go! Take the 2026 Go Developer Survey

basremote

package module
v0.0.0-...-5a59627 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 19, 2026 License: MIT Imports: 19 Imported by: 0

README

bas-remote-go

Go Version License Go Report Card

Go-порт библиотеки bas-remote-python — клиент для удалённого управления функциями BrowserAutomationStudio (BAS) из Go-приложений.

Полная документация по возможностям BAS, созданию пользовательских скриптов и архитектуре протокола доступна в оригинальном репозитории.


Содержание


Установка

go get github.com/zenki-deve/bas-remote-go

Требования: Go 1.21+, Windows (движок BAS работает только под Windows).


Быстрый старт

Пример выполняет поиск в Google через BAS-функцию GoogleSearch из тестового скрипта TestRemoteControl.

package main

import (
	"fmt"
	"log"
	"time"

	basremote "github.com/zenki-deve/bas-remote-go"
)

func main() {
	opts := &basremote.Options{
		ScriptName: "TestRemoteControl",
	}

	client, err := basremote.New(opts)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	// Запуск клиента — загружает движок BAS и подключается по WebSocket.
	if err := client.Start(60 * time.Second); err != nil {
		log.Fatal(err)
	}

	// Запуск BAS-функции и ожидание результата.
	fn, err := client.RunFunction("GoogleSearch", map[string]interface{}{
		"Query": "cats",
	})
	if err != nil {
		log.Fatal(err)
	}

	result := <-fn.Result()
	if result.Err != nil {
		log.Fatal(result.Err)
	}

	fmt.Println("Результат:", string(result.Value))
}

API

basremote.New(opts *Options) (*BasRemoteClient, error)

Создаёт клиент. Принимает *Options:

Поле Тип Описание
ScriptName string Обязательно. Имя BAS-скрипта.
Login string Логин аккаунта BAS с доступом к скрипту.
Password string Пароль аккаунта BAS.
WorkingDir string Папка для хранения движка. По умолчанию <cwd>/data.

client.Start(timeout time.Duration) error

Скачивает движок BAS (если нужно), запускает его и устанавливает WebSocket-соединение. Блокирует до завершения handshake или истечения timeout.


client.RunFunction(name string, params map[string]interface{}) (*BasFunction, error)

Запускает BAS-функцию в отдельном потоке. Результат читается из канала:

fn, err := client.RunFunction("Add", map[string]interface{}{"X": 5, "Y": 3})
if err != nil {
    log.Fatal(err)
}

res := <-fn.Result()
if res.Err != nil {
    log.Fatal(res.Err)
}
fmt.Println("Сумма:", string(res.Value)) // "8"

Метод fn.Stop() немедленно останавливает выполнение.


client.CreateThread() *BasThread

Создаёт переиспользуемый поток BAS. В отличие от RunFunction, поток не останавливается между вызовами — эффективнее для серии задач.

thread := client.CreateThread()
defer thread.Stop()

thread.RunFunction("SetProxy", map[string]interface{}{
    "Proxy":    "127.0.0.1:8080",
    "IsSocks5": false,
})
res := <-thread.Result()

thread.RunFunction("CheckIp", nil)
ip := <-thread.Result()
fmt.Println("IP:", string(ip.Value))

client.Send / client.SendAsync

Низкоуровневые методы для отправки произвольных сообщений протокола BAS:

// Отправить без ожидания ответа, получить ID сообщения.
id, err := client.Send("my_type", map[string]interface{}{"key": "val"}, false)

// Отправить и дождаться ответа.
raw, err := client.SendAsync("get_global_variable", map[string]interface{}{"name": "myVar"})

client.Close() error

Закрывает WebSocket-соединение и завершает процесс движка BAS.


Архитектура

Библиотека повторяет архитектуру bas-remote-python, адаптированную под идиомы Go:

BasRemoteClient
├── engineService   — скачивает zip, распаковывает, запускает FastExecuteScript.exe
├── socketService   — WebSocket-клиент с буферизацией по сепаратору ---Message--End---
├── BasFunction     — одноразовый вызов (goroutine: start_thread → run_task → stop_thread)
└── BasThread       — многоразовый поток (lazy start_thread, atomic isRunning)

Протокол WebSocket:

  • Сообщения сериализуются в JSON и разделяются строкой ---Message--End---.
  • Handshake: initialize → accept_resources → thread_start (готово) / message (ошибка аутентификации).
  • Async-запросы отслеживаются по id через sync.Map[int]chan json.RawMessage.

Вместо asyncio используются goroutine + channel:

Python Go
asyncio.Future chan runResult
asyncio.create_task go func()
await <-ch
AsyncIOEventEmitter внутренний map[string][]func + sync.RWMutex

Движок BAS скачивается автоматически в WorkingDir/engine/<version>/ при первом запуске и переиспользуется в дальнейшем.


Тестовый проект

Скрипт TestRemoteControl доступен для тестирования без BAS-подписки. Он предоставляет следующие функции:

Функция Параметры Возвращает
Add X int, Y int Сумму X + Y
SetProxy Proxy string, IsSocks5 bool —
CheckIp — Внешний IP-адрес
GoogleSearch Query string Список URL результатов
// Пример: сложение
fn, _ := client.RunFunction("Add", map[string]interface{}{"X": 10, "Y": 20})
res := <-fn.Result()
fmt.Println(string(res.Value)) // 30

// Пример: проверка IP
fn2, _ := client.RunFunction("CheckIp", nil)
ip := <-fn2.Result()
fmt.Println(string(ip.Value)) // "1.2.3.4"

Лицензия

MIT — приложения, использующие эту библиотеку, можно распространять коммерчески. Подписка BAS Premium требуется только разработчикам, создающим собственные скрипты, но не конечным пользователям.


Go-порт bablosoft/bas-remote-python • BAS • bablosoft.com

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrSocketNotConnected = errors.New("cannot connect to the WebSocket server")
	ErrScriptNotSupported = errors.New("script engine not supported (required 22.4.2 or newer)")
	ErrClientNotStarted   = errors.New("request can not be sent: client is not started")
	ErrScriptNotExist     = errors.New("script with selected name does not exist")
	ErrAuthentication     = errors.New("unsuccessful authentication")
	ErrAlreadyRunning     = errors.New("another task is already running, unable to start a new one")
)

Functions

This section is empty.

Types

type BasFunction

type BasFunction struct {
	// contains filtered or unexported fields
}

BasFunction represents a one-shot BAS function call. It starts a new thread, runs the function, then stops the thread.

func (*BasFunction) Result

func (r *BasFunction) Result() <-chan runResult

Result returns the channel that delivers exactly one runResult when the task finishes.

func (*BasFunction) Stop

func (f *BasFunction) Stop() error

Stop immediately stops the function's thread.

type BasRemoteClient

type BasRemoteClient struct {
	Options *Options
	// contains filtered or unexported fields
}

BasRemoteClient provides methods for remotely controlling a BAS engine.

func New

func New(opts *Options) (*BasRemoteClient, error)

New creates a new BasRemoteClient. Call Start() to connect.

func (*BasRemoteClient) Close

func (c *BasRemoteClient) Close() error

Close shuts down the WebSocket connection and kills the engine process.

func (*BasRemoteClient) CreateThread

func (c *BasRemoteClient) CreateThread() *BasThread

CreateThread creates a new reusable BAS thread object.

func (*BasRemoteClient) IsStarted

func (c *BasRemoteClient) IsStarted() bool

IsStarted reports whether the client has completed initialisation.

func (*BasRemoteClient) RunFunction

func (c *BasRemoteClient) RunFunction(name string, params map[string]interface{}) (*BasFunction, error)

RunFunction starts a one-shot BAS function call in a new thread.

func (*BasRemoteClient) Send

func (c *BasRemoteClient) Send(type_ string, data map[string]interface{}, async_ bool) (int, error)

Send sends a message and returns its ID.

func (*BasRemoteClient) SendAsync

func (c *BasRemoteClient) SendAsync(type_ string, data map[string]interface{}) (json.RawMessage, error)

SendAsync sends a message and blocks until the response arrives.

func (*BasRemoteClient) Start

func (c *BasRemoteClient) Start(timeout time.Duration) error

Start initialises the engine, connects the WebSocket and waits for the BAS thread_start handshake. timeout ≤ 0 means no timeout.

func (*BasRemoteClient) StartThread

func (c *BasRemoteClient) StartThread(threadID int) error

StartThread sends a start_thread command for the given thread ID.

func (*BasRemoteClient) StopThread

func (c *BasRemoteClient) StopThread(threadID int) error

StopThread sends a stop_thread command for the given thread ID.

type BasThread

type BasThread struct {
	// contains filtered or unexported fields
}

BasThread is a reusable BAS thread. Unlike BasFunction it does not automatically stop after the first function call.

func (*BasThread) IsRunning

func (t *BasThread) IsRunning() bool

IsRunning reports whether the thread is currently executing a function.

func (*BasThread) Result

func (r *BasThread) Result() <-chan runResult

Result returns the channel that delivers exactly one runResult when the task finishes.

func (*BasThread) RunFunction

func (t *BasThread) RunFunction(name string, params map[string]interface{}) (*BasThread, error)

RunFunction queues a BAS function on this thread and returns self for chaining. Returns ErrAlreadyRunning if a function is already executing on this thread.

func (*BasThread) Stop

func (t *BasThread) Stop() error

Stop stops the thread and resets its state.

type FunctionError

type FunctionError struct {
	Msg string
}

FunctionError is returned when BAS reports a function-level failure.

func (*FunctionError) Error

func (e *FunctionError) Error() string

type Message

type Message struct {
	Async bool            `json:"async"`
	Type  string          `json:"type"`
	ID    int             `json:"id"`
	Data  json.RawMessage `json:"data,omitempty"`
}

Message represents a single BAS WebSocket protocol message.

func MessageFromJSON

func MessageFromJSON(s string) (Message, error)

MessageFromJSON deserialises a JSON string into a Message.

func (Message) DataString

func (m Message) DataString() string

DataString returns the raw Data field as a plain string (stripping JSON quotes if it is a JSON string literal).

func (Message) ToJSON

func (m Message) ToJSON() string

ToJSON serialises the message to a JSON string.

type Options

type Options struct {
	// WorkingDir is the directory used to store downloaded engine files.
	// Defaults to <cwd>/data.
	WorkingDir string

	// ScriptName is the name of the private BAS script to connect to.
	ScriptName string

	// Login is the BAS account login with access to the script.
	Login string

	// Password is the BAS account password.
	Password string
}

Options holds client configuration.

type Response

type Response struct {
	Success bool            `json:"Success"`
	Message string          `json:"Message"`
	Result  json.RawMessage `json:"Result"`
}

Response is the payload returned by BAS for async task requests.

func ParseResponse

func ParseResponse(s string) (Response, error)

ParseResponse deserialises a JSON string into a Response.

type Script

type Script struct {
	// contains filtered or unexported fields
}

Script holds metadata returned by the BAS script-properties API.

func NewScript

func NewScript(body []byte) (*Script, error)

NewScript parses the JSON body returned by the properties endpoint.

func (*Script) EngineVersion

func (s *Script) EngineVersion() string

EngineVersion returns the engine version string required by this script.

func (*Script) Hash

func (s *Script) Hash() string

Hash returns the script content hash (first 5 chars used for exe dir naming).

func (*Script) IsExist

func (s *Script) IsExist() bool

IsExist reports whether the script was found.

func (*Script) IsFree

func (s *Script) IsFree() bool

IsFree reports whether the script is freely accessible.

func (*Script) IsSupported

func (s *Script) IsSupported() bool

IsSupported reports whether the engine version meets the minimum requirement (22.4.2+).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL