Skip to content

Commit

Permalink
tmp
Browse files Browse the repository at this point in the history
  • Loading branch information
tulir committed Aug 6, 2023
1 parent bd0bc2c commit c85f425
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 26 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@ insert_final_newline = true
[*.yaml]
indent_style = space

[*.plist]
indent_style = space
indent_size = 2

[{.pre-commit-config.yaml,.github/workflows/*.yaml}]
indent_size = 2
12 changes: 6 additions & 6 deletions bridgeconfig/bridgeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ func init() {
}
}

func templateName(bridgeName string) string {
return fmt.Sprintf("%s.tpl.yaml", bridgeName)
func templateName(bridgeType string) string {
return fmt.Sprintf("%s.tpl.yaml", bridgeType)
}

func IsSupported(bridgeName string) bool {
return tpl.Lookup(templateName(bridgeName)) != nil
func IsSupported(bridgeType string) bool {
return tpl.Lookup(templateName(bridgeType)) != nil
}

func Generate(bridgeName string, params Params) (string, error) {
func Generate(bridgeType string, params Params) (string, error) {
var out strings.Builder
err := tpl.ExecuteTemplate(&out, templateName(bridgeName), &params)
err := tpl.ExecuteTemplate(&out, templateName(bridgeType), &params)
return out.String(), err
}
64 changes: 64 additions & 0 deletions bridgeservice/bridgeservice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package bridgeservice

import (
_ "embed"
"encoding/xml"
"fmt"
"strings"
"text/template"
)

//go:embed systemd.tpl.service
var systemdServiceRaw string
var systemdService *template.Template

//go:embed launchagent.tpl.plist
var launchAgentRaw string
var launchAgent *template.Template

var tplFuncs = map[string]any{
"xmlescape": func(input string) string {
var buf strings.Builder
_ = xml.EscapeText(&buf, []byte(input))
return buf.String()
},
"shelljoin": func(input []string) string {
var buf strings.Builder
for _, arg := range input {
// TODO use proper shell quoting?
_, _ = fmt.Fprintf(&buf, "%q ", arg)
}
return buf.String()[:buf.Len()-1]
},
"join": strings.Join,
}

func init() {
var err error
systemdService, err = template.New("systemdService").Funcs(tplFuncs).Parse(systemdServiceRaw)
if err != nil {
panic(fmt.Errorf("failed to parse systemd service template: %w", err))
}
launchAgent, err = template.New("launchAgent").Funcs(tplFuncs).Parse(launchAgentRaw)
if err != nil {
panic(fmt.Errorf("failed to parse LaunchAgent template: %w", err))
}
}

type Params struct {
BridgeType string
Name string
WorkDir string
}

func Systemd(params Params) (string, error) {
var out strings.Builder
err := systemdService.Execute(&out, &params)
return out.String(), err
}

func LaunchAgent(params Params) (string, error) {
var out strings.Builder
err := launchAgent.Execute(&out, &params)
return out.String(), err
}
23 changes: 23 additions & 0 deletions bridgeservice/launchagent.tpl.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.beeper.bbctl.{{ xmlescape .Name }}</string>
<key>ProgramArguments</key>
<array>
<string>bbctl</string>
<string>run</string>
{{ range .Args }}
<string>{{ xmlescape . }}</string>
{{ end }}
<string>{{ xmlescape .Name }}</string>
</array>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>{{ .WorkDir }}</string>
</dict>
</plist>
11 changes: 11 additions & 0 deletions bridgeservice/systemd.tpl.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description=Beeper {{ .BridgeType }} ({{ .Name }})
After=network.target

[Service]
Type=simple
WorkingDirectory={{ .WorkDir }}
ExecStart=bbctl run {{ shelljoin .Args }} "{{ .Name }}"

[Install]
WantedBy=default.target
2 changes: 1 addition & 1 deletion cmd/bbctl/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func doGenerateBridgeConfig(ctx *cli.Context, bridge string) (*generatedBridgeCo
if err != nil {
return nil, err
}
if len(extraParams) != len(cliParams) {
if len(extraParams) != len(cliParams) && ctx.Command != installServiceCommand {
formattedParams := make([]string, 0, len(extraParams))
for key, value := range extraParams {
_, isCli := cliParams[key]
Expand Down
66 changes: 66 additions & 0 deletions cmd/bbctl/install-service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"os"
"runtime"

"github.com/urfave/cli/v2"
)

var installServiceCommand = &cli.Command{

Check failure on line 10 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / lint

initialization cycle for installServiceCommand

Check failure on line 10 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / lint

installServiceCommand refers to

Check failure on line 10 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / lint

installServiceCommand

Check failure on line 10 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / build

initialization cycle for installServiceCommand

Check failure on line 10 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / build

installServiceCommand refers to

Check failure on line 10 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / build

installServiceCommand

Check failure on line 10 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / build

initialization cycle for installServiceCommand

Check failure on line 10 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / build

installServiceCommand refers to
Name: "install-service",
Usage: "Install a system service file to run an official Beeper bridge",
ArgsUsage: "BRIDGE",
Before: RequiresAuth,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
Aliases: []string{"t"},
EnvVars: []string{"BEEPER_BRIDGE_TYPE"},
Usage: "The type of bridge to run.",
},
&cli.StringSliceFlag{
Name: "param",
Aliases: []string{"p"},
Usage: "Set a bridge-specific config generation option. Can be specified multiple times for different keys. Format: key=value",
},
&cli.BoolFlag{
Name: "no-update",
Aliases: []string{"n"},
Usage: "Don't update the bridge even if it is out of date.",
EnvVars: []string{"BEEPER_BRIDGE_NO_UPDATE"},
},
&cli.BoolFlag{
Name: "force",
Aliases: []string{"f"},
Usage: "Force register a bridge without the sh- prefix (dangerous).",
Hidden: true,
},
},
Action: installService,
}

func isSystemd() bool {
stat, err := os.Stat("/run/systemd/system")
return err == nil && stat.IsDir()
}

func installService(ctx *cli.Context) error {

Check failure on line 48 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / lint

installService refers to

Check failure on line 48 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / build

installService refers to

Check failure on line 48 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / build

installService refers to
if ctx.NArg() == 0 {
return UserError{"You must specify a bridge to install"}
} else if ctx.NArg() > 1 {
return UserError{"Too many arguments specified (flags must come before arguments)"}
}
bridgeName := ctx.Args().Get(0)
installed, err := doInstallBridge(ctx, bridgeName, true)

Check failure on line 55 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / lint

installed declared and not used (compile)

Check failure on line 55 in cmd/bbctl/install-service.go

View workflow job for this annotation

GitHub Actions / build

installed declared and not used
if err != nil {
return err
}
switch {
case runtime.GOOS == "darwin":
case isSystemd():
default:
return UserError{"No supported init systems found"}
}
return nil
}
1 change: 1 addition & 0 deletions cmd/bbctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ var app = &cli.App{
whoamiCommand,
configCommand,
runCommand,
installServiceCommand,
},
}

Expand Down
58 changes: 39 additions & 19 deletions cmd/bbctl/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,67 +132,87 @@ func makeCmd(ctx context.Context, pwd, path string, args ...string) *exec.Cmd {
return cmd
}

func runBridge(ctx *cli.Context) error {
if ctx.NArg() == 0 {
return UserError{"You must specify a bridge to run"}
} else if ctx.NArg() > 1 {
return UserError{"Too many arguments specified (flags must come before arguments)"}
}
bridgeName := ctx.Args().Get(0)
type installedBridge struct {
Dir string
Cmd string
Args []string
Cfg *generatedBridgeConfig
}

func doInstallBridge(ctx *cli.Context, bridgeName string, installBinary bool) (*installedBridge, error) {

Check failure on line 142 in cmd/bbctl/run.go

View workflow job for this annotation

GitHub Actions / lint

doInstallBridge refers to

Check failure on line 142 in cmd/bbctl/run.go

View workflow job for this annotation

GitHub Actions / build

doInstallBridge refers to
cfg, err := doGenerateBridgeConfig(ctx, bridgeName)
if err != nil {
return err
return nil, err
}

dataDir := GetEnvConfig(ctx).BridgeDataDir
bridgeDir := filepath.Join(dataDir, bridgeName)
err = os.MkdirAll(bridgeDir, 0700)
if err != nil {
return err
return nil, err
}

err = os.WriteFile(filepath.Join(bridgeDir, "config.yaml"), []byte(cfg.Config), 0600)
if err != nil {
return fmt.Errorf("failed to save config: %w", err)
return nil, fmt.Errorf("failed to save config: %w", err)
}

overrideBridgeCmd := ctx.String("custom-startup-command")
var bridgeCmd string
var bridgeArgs []string
switch cfg.BridgeType {
case "imessage", "whatsapp", "discord", "slack", "gmessages":
bridgeCmd = filepath.Join(dataDir, "binaries", fmt.Sprintf("mautrix-%s", cfg.BridgeType))
if overrideBridgeCmd == "" {
if installBinary {
err = updateGoBridge(ctx.Context, bridgeCmd, cfg.BridgeType, ctx.Bool("no-update"))
if err != nil {
return fmt.Errorf("failed to update bridge: %w", err)
return nil, fmt.Errorf("failed to update bridge: %w", err)
}
}
case "heisenbridge":
if overrideBridgeCmd == "" {
if installBinary {
err = setupPythonVenv(ctx.Context, bridgeDir, cfg.BridgeType)
if err != nil {
return fmt.Errorf("failed to update bridge: %w", err)
return nil, fmt.Errorf("failed to update bridge: %w", err)
}
}
heisenHomeserverURL := strings.Replace(cfg.HomeserverURL, "https://", "wss://", 1)
bridgeCmd = filepath.Join(bridgeDir, "venv", "bin", "python3")
bridgeArgs = []string{"-m", "heisenbridge", "-c", "config.yaml", "-o", cfg.YourUserID.String(), heisenHomeserverURL}
}
return &installedBridge{
Dir: bridgeDir,
Cmd: bridgeCmd,
Args: bridgeArgs,
Cfg: cfg,
}, nil
}

func runBridge(ctx *cli.Context) error {
if ctx.NArg() == 0 {
return UserError{"You must specify a bridge to run"}
} else if ctx.NArg() > 1 {
return UserError{"Too many arguments specified (flags must come before arguments)"}
}
bridgeName := ctx.Args().Get(0)
overrideBridgeCmd := ctx.String("custom-startup-command")

installed, err := doInstallBridge(ctx, bridgeName, overrideBridgeCmd == "")
if err != nil {
return err
}
if overrideBridgeCmd != "" {
bridgeCmd = overrideBridgeCmd
installed.Cmd = overrideBridgeCmd
}

cmd := makeCmd(ctx.Context, bridgeDir, bridgeCmd, bridgeArgs...)
log.Printf("Starting [cyan]%s[reset]", cfg.BridgeType)
cmd := makeCmd(ctx.Context, installed.Dir, installed.Cmd, installed.Args...)
log.Printf("Starting [cyan]%s[reset]", installed.Cfg.BridgeType)

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)

go func() {
<-c
log.Printf("Shutting down [cyan]%s[reset]", cfg.BridgeType)
log.Printf("Shutting down [cyan]%s[reset]", installed.Cfg.BridgeType)
proc := cmd.Process
if proc != nil {
err := proc.Signal(syscall.SIGTERM)
Expand Down

0 comments on commit c85f425

Please sign in to comment.