daemon.go 2.75 KB
Newer Older
1 2 3 4
package daemon

import (
	"encoding/json"
5
	"fmt"
6
	"io"
7
	"net"
8
	"os"
9

10
	core "github.com/jbenet/go-ipfs/core"
11
	"github.com/jbenet/go-ipfs/core/commands"
12
	u "github.com/jbenet/go-ipfs/util"
13
	"github.com/op/go-logging"
14

15
	"github.com/camlistore/lock"
16
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
17 18
)

19 20
var log = logging.MustGetLogger("daemon")

21 22
// DaemonListener listens to an initialized IPFS node and can send it commands instead of
// starting up a new set of connections
23
type DaemonListener struct {
24 25 26
	node   *core.IpfsNode
	list   net.Listener
	closed bool
27
	lk     io.Closer
28 29
}

Siraj Ravel's avatar
Siraj Ravel committed
30
//Command accepts user input and can be sent to the running IPFS node
Siraj Ravel's avatar
Siraj Ravel committed
31 32 33 34 35 36
type Command struct {
	Command string
	Args    []string
	Opts    map[string]interface{}
}

37 38 39 40 41 42 43 44 45 46 47 48
func NewDaemonListener(ipfsnode *core.IpfsNode, addr *ma.Multiaddr, confdir string) (*DaemonListener, error) {
	var err error
	confdir, err = u.TildeExpansion(confdir)
	if err != nil {
		return nil, err
	}

	lk, err := lock.Lock(confdir + "/daemon.lock")
	if err != nil {
		return nil, err
	}

49 50 51 52 53
	network, host, err := addr.DialArgs()
	if err != nil {
		return nil, err
	}

54 55 56 57 58 59 60 61 62 63 64 65 66
	ofi, err := os.Create(confdir + "/rpcaddress")
	if err != nil {
		log.Warning("Could not create rpcaddress file: %s", err)
		return nil, err
	}

	_, err = ofi.Write([]byte(host))
	if err != nil {
		log.Warning("Could not write to rpcaddress file: %s", err)
		return nil, err
	}
	ofi.Close()

67
	list, err := net.Listen(network, host)
68 69 70
	if err != nil {
		return nil, err
	}
71
	log.Info("New daemon listener initialized.")
72 73

	return &DaemonListener{
Siraj Ravel's avatar
Siraj Ravel committed
74
		node: ipfsnode,
75
		list: list,
76
		lk:   lk,
77 78 79
	}, nil
}

80 81 82 83
func NewCommand() *Command {
	return &Command{
		Opts: make(map[string]interface{}),
	}
84 85 86
}

func (dl *DaemonListener) Listen() {
87
	fmt.Println("listen.")
88
	for {
Siraj Ravel's avatar
Siraj Ravel committed
89
		conn, err := dl.list.Accept()
90
		fmt.Println("Loop!")
91 92 93 94
		if err != nil {
			if !dl.closed {
				u.PErr("DaemonListener Accept: %v\n", err)
			}
95
			dl.lk.Close()
96 97
			return
		}
Siraj Ravel's avatar
Siraj Ravel committed
98
		go dl.handleConnection(conn)
99 100 101
	}
}

Siraj Ravel's avatar
Siraj Ravel committed
102 103
func (dl *DaemonListener) handleConnection(conn net.Conn) {
	defer conn.Close()
104

Siraj Ravel's avatar
Siraj Ravel committed
105
	dec := json.NewDecoder(conn)
106

Siraj Ravel's avatar
Siraj Ravel committed
107 108
	var command Command
	err := dec.Decode(&command)
109
	if err != nil {
Siraj Ravel's avatar
Siraj Ravel committed
110
		fmt.Fprintln(conn, err)
111 112
		return
	}
113

Siraj Ravel's avatar
Siraj Ravel committed
114
	u.DOut("Got command: %v\n", command)
115
	switch command.Command {
116
	case "add":
117
		err = commands.Add(dl.node, command.Args, command.Opts, conn)
118
	case "cat":
119
		err = commands.Cat(dl.node, command.Args, command.Opts, conn)
120
	case "ls":
121
		err = commands.Ls(dl.node, command.Args, command.Opts, conn)
Jeromy's avatar
Jeromy committed
122
	case "pin":
123
		err = commands.Pin(dl.node, command.Args, command.Opts, conn)
124
	default:
125 126 127 128
		err = fmt.Errorf("Invalid Command: '%s'", command.Command)
	}
	if err != nil {
		fmt.Fprintln(conn, err)
129 130 131 132 133 134 135
	}
}

func (dl *DaemonListener) Close() error {
	dl.closed = true
	return dl.list.Close()
}