ricochet-go/cli/cli.go

138 lines
3.1 KiB
Go
Raw Normal View History

2016-08-02 04:58:10 +02:00
package main
import (
2016-10-16 23:50:34 +02:00
"bytes"
"flag"
"fmt"
2016-10-23 20:37:57 +02:00
"github.com/chzyer/readline"
ricochet "github.com/ricochet-im/ricochet-go/core"
2016-10-17 06:26:35 +02:00
rpc "github.com/ricochet-im/ricochet-go/rpc"
2016-08-02 04:58:10 +02:00
"google.golang.org/grpc"
"log"
"net"
"os"
"strings"
"time"
2016-08-02 04:58:10 +02:00
)
var (
LogBuffer bytes.Buffer
2016-08-02 04:58:10 +02:00
// Flags
backendAddress string
unsafeBackend bool
)
2016-10-16 23:50:34 +02:00
func main() {
flag.StringVar(&backendAddress, "backend", "", "Connect to the client backend running on `address`")
flag.BoolVar(&unsafeBackend, "allow-unsafe-backend", false, "Allow a remote backend address. This is NOT RECOMMENDED and may harm your security or privacy. Do not use without a secure, trusted link")
flag.Parse()
// Set up readline
2016-10-26 23:26:21 +02:00
input, err := readline.NewEx(&readline.Config{
InterruptPrompt: "^C",
EOFPrompt: "exit",
})
2016-08-03 01:28:26 +02:00
if err != nil {
2016-10-16 23:50:34 +02:00
fmt.Println(err)
os.Exit(1)
2016-08-03 01:28:26 +02:00
}
2016-10-16 23:50:34 +02:00
defer input.Close()
log.SetOutput(&LogBuffer)
2016-08-03 01:28:26 +02:00
// Connect to RPC backend, start in-process backend if necessary
conn, err := connectClientBackend()
if err != nil {
fmt.Printf("backend failed: %v\n", err)
os.Exit(1)
}
2016-10-16 23:50:34 +02:00
defer conn.Close()
// Configure client and UI
client := &Client{
Backend: rpc.NewRicochetCoreClient(conn),
}
2016-10-23 02:50:21 +02:00
Ui = UI{
Input: input,
Stdout: input.Stdout(),
Client: client,
}
// Initialize data from backend and start UI command loop
2016-10-16 23:50:34 +02:00
fmt.Print("Connecting to backend...\n")
go func() {
if err := client.Initialize(); err != nil {
fmt.Printf("Error: %s\n", err)
os.Exit(1)
}
client.Block()
2016-10-23 02:50:21 +02:00
Ui.PrintStatus()
2016-10-16 23:50:34 +02:00
client.Unblock()
}()
2016-10-23 02:50:21 +02:00
Ui.CommandLoop()
2016-08-02 04:58:10 +02:00
}
func connectClientBackend() (*grpc.ClientConn, error) {
if backendAddress == "" {
// In-process backend, using 'InnerNet' as a fake socket
address, err := startLocalBackend()
if err != nil {
return nil, err
}
return grpc.Dial(address, grpc.WithInsecure(), grpc.WithDialer(DialInnerNet))
} else {
// External backend
if strings.HasPrefix(backendAddress, "unix:") {
return grpc.Dial(backendAddress[5:], grpc.WithInsecure(),
grpc.WithDialer(func(address string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", address, timeout)
}))
} else {
host, _, err := net.SplitHostPort(backendAddress)
if err != nil {
return nil, err
}
ip := net.ParseIP(host)
if !unsafeBackend && (ip == nil || !ip.IsLoopback()) {
return nil, fmt.Errorf("Host '%s' is not a loopback address.\nRead the warnings and use -allow-unsafe-backend for non-local addresses", host)
}
return grpc.Dial(backendAddress, grpc.WithInsecure())
}
}
}
func startLocalBackend() (string, error) {
config, err := ricochet.LoadConfig(".")
if err != nil {
return "", err
}
core := new(ricochet.Ricochet)
if err := core.Init(config); err != nil {
return "", err
}
listener, err := ListenInnerNet("ricochet.rpc")
if err != nil {
return "", err
}
server := &ricochet.RpcServer{
Core: core,
}
go func() {
grpcServer := grpc.NewServer()
rpc.RegisterRicochetCoreServer(grpcServer, server)
err := grpcServer.Serve(listener)
if err != nil {
log.Printf("backend exited: %v", err)
os.Exit(1)
}
}()
return "ricochet.rpc", nil
}