omegafox/legacy/launcher/load-addons.go
2024-11-21 18:51:27 -06:00

157 lines
3.2 KiB
Go

package main
import (
"bufio"
"encoding/json"
"fmt"
"net"
"os"
"strconv"
"strings"
"time"
)
// Gets the debug port from the args, or creates a new one if not provided
func getDebugPort(args *[]string) int {
debugPort := parseArgs("-start-debugger-server", "", args, false)
var debugPortInt int
var err error
if debugPort == "" {
// Create new debugger server port
debugPortInt = getOpenPort()
// Add -start-debugger-server {debugPort} to args
*args = append(*args, "-start-debugger-server", strconv.Itoa(debugPortInt))
} else {
debugPortInt, err = strconv.Atoi(debugPort)
if err != nil {
fmt.Printf("Error parsing debug port. Must be an integer: %v\n", err)
os.Exit(1)
}
}
return debugPortInt
}
// Confirm paths are valid
func confirmPaths(paths []string) {
for _, path := range paths {
if _, err := os.Stat(path); err != nil {
fmt.Printf("Error: %s is not a valid addon path.\n", path)
os.Exit(1)
}
}
}
// Generate an open port
func getOpenPort() int {
ln, err := net.Listen("tcp", ":0") // listen on a random port
if err != nil {
return 0
}
defer ln.Close()
addr := ln.Addr().(*net.TCPAddr) // type assert to *net.TCPAddr to get the Port
return addr.Port
}
// Waits for the server to start, then loads the addons
func tryLoadAddons(debugPortInt int, addonsList []string) {
// Wait for the server to be open
for {
conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", debugPortInt))
if err == nil {
conn.Close()
break
}
time.Sleep(10 * time.Millisecond)
}
// Load addons
for _, addon := range addonsList {
go loadFirefoxAddon(debugPortInt, addon)
}
}
// Firefox addon loader
// Ported from this Nodejs implementation:
// https://github.com/microsoft/playwright/issues/7297#issuecomment-1211763085
func loadFirefoxAddon(port int, addonPath string) bool {
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", "localhost", port))
if err != nil {
return false
}
defer conn.Close()
success := false
send := func(data map[string]string) error {
jsonData, err := json.Marshal(data)
if err != nil {
return err
}
_, err = fmt.Fprintf(conn, "%d:%s", len(jsonData), jsonData)
return err
}
err = send(map[string]string{
"to": "root",
"type": "getRoot",
})
if err != nil {
return false
}
onMessage := func(message map[string]interface{}) bool {
if addonsActor, ok := message["addonsActor"].(string); ok {
err := send(map[string]string{
"to": addonsActor,
"type": "installTemporaryAddon",
"addonPath": addonPath,
})
if err != nil {
return true
}
}
if _, ok := message["addon"]; ok {
success = true
return true
}
if _, ok := message["error"]; ok {
return true
}
return false
}
reader := bufio.NewReader(conn)
for {
lengthStr, err := reader.ReadString(':')
if err != nil {
break
}
length, err := strconv.Atoi(strings.TrimSuffix(lengthStr, ":"))
if err != nil {
break
}
jsonData := make([]byte, length)
_, err = reader.Read(jsonData)
if err != nil {
break
}
var message map[string]interface{}
err = json.Unmarshal(jsonData, &message)
if err != nil {
break
}
if onMessage(message) {
break
}
}
return success
}