Files
zerocontrol/launch.go

427 lines
8.7 KiB
Go

package zerocontrol
/*
Released under the The MIT License (MIT)
see ./LICENSE
*/
import (
"context"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
)
import (
"github.com/eyedeekay/checki2cp"
)
var i2cpConf = `i2cp.tcp4.host=127.0.0.1
i2cp.tcp4.port=7654
`
var zd, _ = UnpackZeroDir()
var baseargs = "--i2p.dir.base=" + filepath.Join(zd, "base")
var configargs = "--i2p.dir.config=" + filepath.Join(zd, "config")
func WriteI2CPConf() error {
dir, err := UnpackZeroDir()
if err != nil {
return err
}
os.Setenv("I2CP_HOME", dir)
os.Setenv("GO_I2CP_CONF", "/.i2cp.conf")
home := os.Getenv("I2CP_HOME")
conf := os.Getenv("GO_I2CP_CONF")
if err := ioutil.WriteFile(filepath.Join(home, conf), []byte(i2cpConf), 0644); err != nil {
return err
}
return nil
}
func ZeroMain() error {
if err := WriteI2CPConf(); err != nil {
return err
}
if ok, err := checki2p.CheckI2PIsRunning(); err == nil {
if err != nil {
return err
}
if ok {
return nil
}
}
if ok, err := checki2p.ConditionallyLaunchI2P(); ok {
if err != nil {
return err
}
} else {
if err := UnpackZero(); err != nil {
log.Println(err)
}
latest := LatestZero()
log.Println("latest zero version is:", latest)
if !CheckZeroIsRunning() {
log.Println("Zero doesn't appear to be running.", latest)
if err := StartZero(); err != nil {
return err
}
} else {
return nil
}
if ok, conn := Available(); ok {
log.Println("Starting SAM")
time.Sleep(3 * time.Second)
if err := SAM(conn); err != nil {
return err
}
} else {
return fmt.Errorf("I2P router availability failure")
}
if ok, conn := Available(); ok {
log.Println("Starting HTTP Proxy")
time.Sleep(3 * time.Second)
if err := PROXY(conn); err != nil {
return err
}
} else {
return fmt.Errorf("I2P router availability failure")
}
}
time.Sleep(1 * time.Second)
return nil
}
var cmd *exec.Cmd
func LoopbackInterface() string {
if runtime.GOOS != "windows" {
return "127.0.0.1"
}
ift, err := net.Interfaces()
if err != nil {
return "localhost"
}
log.Println("Searching for appropriate loopback interface")
for _, ifi := range ift {
if ifi.Flags&net.FlagLoopback != 0 && ifi.Flags&net.FlagUp != 0 {
log.Println("Searching", ifi.Name)
a, err := ifi.Addrs()
if err != nil {
return "localhost"
}
if !strings.Contains(a[0].String(), "::") {
return strings.Split(a[0].String(), "/")[0]
}
}
}
return "localhost"
}
func CheckZeroIsRunning() bool {
conn, err := net.Dial("tcp4", net.JoinHostPort(LoopbackInterface(), "8051"))
if err != nil {
log.Println("Connecting error:", err)
}
if conn != nil {
defer conn.Close()
return true
}
return false
}
func GetZeroCMD() *exec.Cmd {
return cmd
}
func GetZeroPID() int {
return cmd.Process.Pid
}
func GetZeroProcess() *os.Process {
return cmd.Process
}
func LatestZero() string {
if runtime.GOOS == "windows" {
return filepath.Join(LatestZeroBinDir(), "i2p-zero.exe")
} else if runtime.GOOS == "darwin" {
return filepath.Join(LatestZeroBinDir(), "launch.sh")
} else {
return filepath.Join(LatestZeroBinDir(), "i2p-zero")
}
}
func LatestZeroJavaHome() string {
if runtime.GOOS == "windows" {
return filepath.Join(LatestZeroBinDirJavaHome(), "i2p-zero.exe")
} else if runtime.GOOS == "darwin" {
return filepath.Join(LatestZeroBinDirJavaHome(), "launch.sh")
} else {
return filepath.Join(LatestZeroBinDirJavaHome(), "i2p-zero")
}
}
func LatestZeroDir() string {
var dir string
var err error
if dir, err = UnpackZeroDir(); err == nil {
ks, er := ioutil.ReadDir(dir)
fs := []os.FileInfo{}
for _, k := range ks {
if k.IsDir() {
if strings.Contains(k.Name(), "i2p-zero-") {
fs = append(fs, k)
}
}
}
if er != nil {
log.Fatal(er)
}
return filepath.Join(dir, fs[len(fs)-1].Name())
} else {
log.Fatal(err)
}
return ""
}
func LatestZeroBinDir() string {
var dir string
var err error
if dir, err = UnpackZeroDir(); err == nil {
ks, er := ioutil.ReadDir(dir)
fs := []os.FileInfo{}
for _, k := range ks {
if k.IsDir() {
if strings.Contains(k.Name(), "i2p-zero-") {
fs = append(fs, k)
}
}
}
if er != nil {
log.Fatal(er)
}
if runtime.GOOS == "windows" {
return filepath.Join(dir, fs[len(fs)-1].Name(), "router")
} else if runtime.GOOS == "darwin" {
return filepath.Join(dir, fs[len(fs)-1].Name(), "router", "bin")
} else {
return filepath.Join(dir, fs[len(fs)-1].Name(), "router", "bin")
}
} else {
log.Fatal(err)
}
return ""
}
func LatestZeroDirJavaHome() string {
ks, er := ioutil.ReadDir(JAVA_I2P_OPT_DIR)
fs := []os.FileInfo{}
for _, k := range ks {
if k.IsDir() {
if strings.Contains(k.Name(), "i2p-zero-") {
fs = append(fs, k)
}
}
}
if er != nil {
log.Fatal(er)
}
return filepath.Join(JAVA_I2P_OPT_DIR, fs[len(fs)-1].Name())
}
func LatestZeroBinDirJavaHome() string {
ks, er := ioutil.ReadDir(JAVA_I2P_OPT_DIR)
fs := []os.FileInfo{}
for _, k := range ks {
if k.IsDir() {
if strings.Contains(k.Name(), "i2p-zero-") {
fs = append(fs, k)
}
}
}
if er != nil {
log.Fatal(er)
}
if runtime.GOOS == "windows" {
return filepath.Join(JAVA_I2P_OPT_DIR, fs[len(fs)-1].Name(), "router")
} else if runtime.GOOS == "darwin" {
return filepath.Join(JAVA_I2P_OPT_DIR, fs[len(fs)-1].Name(), "router", "bin")
} else {
return filepath.Join(JAVA_I2P_OPT_DIR, fs[len(fs)-1].Name(), "router", "bin")
}
}
func StopZero() {
if runtime.GOOS == "windows" {
GetZeroProcess().Signal(os.Kill)
} else {
GetZeroProcess().Signal(os.Interrupt)
}
}
func CommandZero() (*exec.Cmd, error) {
if err := UnpackZero(); err != nil {
log.Println(err)
}
latest := LatestZero()
cmd = exec.Command(latest, baseargs, configargs)
cmd.Dir = LatestZeroDir()
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd, nil
}
func CommandZeroContext(ctx context.Context) (*exec.Cmd, error) {
if err := UnpackZero(); err != nil {
log.Println(err)
}
latest := LatestZero()
cmd = exec.CommandContext(ctx, latest, baseargs, configargs)
cmd.Dir = LatestZeroDir()
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd, nil
}
func RunZero() error {
var err error
cmd, err = CommandZero()
if err != nil {
return err
}
return cmd.Run()
}
func StartZero() error {
var err error
cmd, err = CommandZero()
if err != nil {
return err
}
return cmd.Start()
}
func CommandZeroJavaHome() (*exec.Cmd, error) {
if err := UnpackZeroJavaHome(); err != nil {
log.Println(err)
}
latest := LatestZeroJavaHome()
cmd = exec.Command(latest)
cmd.Dir = LatestZeroDirJavaHome()
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd, nil
}
func CommandZeroJavaHomeContext(ctx context.Context) (*exec.Cmd, error) {
if err := UnpackZeroJavaHome(); err != nil {
log.Println(err)
}
latest := LatestZeroJavaHome()
cmd = exec.CommandContext(ctx, latest)
cmd.Dir = LatestZeroDirJavaHome()
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd, nil
}
func RunZeroJavaHome() error {
var err error
cmd, err = CommandZeroJavaHome()
if err != nil {
return err
}
return cmd.Run()
}
func StartZeroJavaHome() error {
var err error
cmd, err = CommandZeroJavaHome()
if err != nil {
return err
}
return cmd.Start()
}
func Available() (bool, net.Conn) {
i := 0
for {
conn, err := net.Dial("tcp4", net.JoinHostPort(LoopbackInterface(), "8051"))
if err != nil {
log.Println("Connecting error:", err)
}
if conn != nil {
log.Println("Zero is started.", err)
return true, conn
}
i++
time.Sleep(time.Duration(5) * time.Second)
}
return false, nil
}
func SAM(conn net.Conn) error {
defer conn.Close()
if runtime.GOOS == "windows" {
conn.Write([]byte("sam.create\r\n"))
} else {
conn.Write([]byte("sam.create\n"))
}
i := 0
for {
samconn, err := net.Dial("tcp4", net.JoinHostPort(LoopbackInterface(), "7656"))
if err != nil {
log.Println("Connecting error:", err)
}
if samconn != nil {
log.Println("Started SAM.")
conn.Close()
return nil
}
i++
time.Sleep(time.Duration(5) * time.Second)
}
return fmt.Errorf("Error connecting to %s", "SAM port")
}
func PROXY(conn net.Conn) error {
defer conn.Close()
if runtime.GOOS == "windows" {
conn.Write([]byte("http.create 4444\r\n"))
} else {
conn.Write([]byte("http.create 4444\n"))
}
i := 0
for {
proxyconn, err := net.Dial("tcp4", net.JoinHostPort(LoopbackInterface(), "4444"))
if err != nil {
log.Println("Connecting error:", err)
}
if proxyconn != nil {
log.Println("Started HTTP Proxy.")
conn.Close()
return nil
}
i++
time.Sleep(time.Duration(5) * time.Second)
}
return nil
}
func Close() error {
if runtime.GOOS == "windows" {
return cmd.Process.Kill()
}
return cmd.Process.Signal(os.Interrupt)
}