portal/bao/bao.go

166 lines
3.0 KiB
Go
Raw Normal View History

package bao
import (
_ "embed"
"github.com/hashicorp/go-plugin"
"io"
"io/fs"
"log"
"os"
"os/exec"
"os/signal"
"syscall"
)
//go:generate protoc --proto_path=proto/ bao.proto --go_out=proto --go_opt=paths=source_relative --go-grpc_out=proto --go-grpc_opt=paths=source_relative
//go:embed target/release/bao
var baoPlugin []byte
var baoInstance Bao
type Bao interface {
Init() (uint32, error)
Write(id uint32, data []byte) error
Finalize(id uint32) ([]byte, error)
Destroy(id uint32) error
2023-05-15 19:45:05 +00:00
ComputeFile(path string) ([]byte, error)
}
func init() {
baoExec, err := os.CreateTemp("", "lumeportal")
_, err = baoExec.Write(baoPlugin)
if err != nil {
log.Fatalf("Error:", err.Error())
}
err = baoExec.Sync()
if err != nil {
log.Fatalf("Error:", err.Error())
}
err = baoExec.Chmod(fs.ModePerm)
if err != nil {
log.Fatalf("Error:", err.Error())
}
err = baoExec.Close()
if err != nil {
log.Fatalf("Error:", err.Error())
}
pluginMap := map[string]plugin.Plugin{
"bao": &BAOPlugin{},
}
client := plugin.NewClient(&plugin.ClientConfig{
HandshakeConfig: plugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "foo",
MagicCookieValue: "bar",
},
Plugins: pluginMap,
Cmd: exec.Command("sh", "-c", baoExec.Name()),
AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
})
// Connect via RPC
rpcClient, err := client.Client()
if err != nil {
log.Fatalf("Error:", err.Error())
}
// Request the plugin
raw, err := rpcClient.Dispense("bao")
if err != nil {
log.Fatalf("Error:", err.Error())
}
baoInstance = raw.(Bao)
signalCh := make(chan os.Signal, 1)
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
go func() {
<-signalCh
err := os.Remove(baoExec.Name())
if err != nil {
log.Fatalf("Error:", err.Error())
}
}()
}
2023-05-15 19:45:05 +00:00
func ComputeTreeStreaming(reader io.Reader) ([]byte, error) {
instance, err := baoInstance.Init()
if err != nil {
return nil, err
}
b := make([]byte, 512)
for {
n, err := reader.Read(b)
if n > 0 {
err := write(instance, &b)
if err != nil {
return nil, err
}
}
if err != nil {
var result []byte
if err == io.EOF {
result, err = finalize(instance)
if err == nil {
return result, nil
}
}
return nil, err
}
}
}
2023-05-15 19:45:05 +00:00
func ComputeTreeFile(file *os.File) ([]byte, error) {
tree, err := baoInstance.ComputeFile(file.Name())
if err != nil {
return nil, err
}
return tree, nil
}
func write(instance uint32, bytes *[]byte) error {
err := baoInstance.Write(instance, *bytes)
if err != nil {
derr := destroy(instance)
if derr != nil {
return derr
}
return err
}
if err != nil {
derr := destroy(instance)
if derr != nil {
return derr
}
return err
}
return nil
}
func finalize(instance uint32) ([]byte, error) {
result, err := baoInstance.Finalize(instance)
if err != nil {
derr := destroy(instance)
if derr != nil {
return nil, derr
}
return nil, err
}
return result, nil
}
func destroy(instance uint32) error {
return baoInstance.Destroy(instance)
}