Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

# -*- coding: utf-8 -*- 

# 

# Copyright (C) 2008-2009 Andrew Resch <andrewresch@gmail.com> 

# 

# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with 

# the additional special exception to link portions of this program with the OpenSSL library. 

# See LICENSE for more details. 

# 

 

import base64 

import logging 

import os 

import sys 

from glob import glob 

from tempfile import mkstemp 

from urllib import url2pathname 

from urlparse import urlparse 

 

import twisted.internet.error 

from twisted.internet import reactor 

from twisted.internet.protocol import ClientFactory, Factory, Protocol 

 

import deluge.component as component 

from deluge.common import is_magnet, is_url, windows_check 

from deluge.configmanager import ConfigManager, get_config_dir 

from deluge.ui.client import client 

 

try: 

    import rencode 

except ImportError: 

    import deluge.rencode as rencode 

 

log = logging.getLogger(__name__) 

 

 

class IPCProtocolServer(Protocol): 

    def dataReceived(self, data):  # NOQA 

        config = ConfigManager("gtkui.conf") 

        data = rencode.loads(data, decode_utf8=True) 

        if not data or config["focus_main_window_on_add"]: 

            component.get("MainWindow").present() 

        process_args(data) 

 

 

class IPCProtocolClient(Protocol): 

    def connectionMade(self):  # NOQA 

        self.transport.write(rencode.dumps(self.factory.args)) 

        self.transport.loseConnection() 

 

    def connectionLost(self, reason):  # NOQA 

        reactor.stop() 

        self.factory.stop = True 

 

 

class IPCClientFactory(ClientFactory): 

    protocol = IPCProtocolClient 

 

    def __init__(self): 

        self.stop = False 

 

    def clientConnectionFailed(self, connector, reason):  # NOQA 

        log.warning("Connection to running instance failed.") 

        reactor.stop() 

 

 

class IPCInterface(component.Component): 

    def __init__(self, args): 

        component.Component.__init__(self, "IPCInterface") 

        ipc_dir = get_config_dir("ipc") 

        if not os.path.exists(ipc_dir): 

            os.makedirs(ipc_dir) 

        socket = os.path.join(ipc_dir, "deluge-gtk") 

        if windows_check(): 

            # If we're on windows we need to check the global mutex to see if deluge is 

            # already running. 

            import win32event 

            import win32api 

            import winerror 

            self.mutex = win32event.CreateMutex(None, False, "deluge") 

            if win32api.GetLastError() != winerror.ERROR_ALREADY_EXISTS: 

                # Create listen socket 

                self.factory = Factory() 

                self.factory.protocol = IPCProtocolServer 

                import random 

                port = random.randrange(20000, 65535) 

                reactor.listenTCP(port, self.factory) 

                # Store the port number in the socket file 

                open(socket, "w").write(str(port)) 

                # We need to process any args when starting this process 

                process_args(args) 

            else: 

                # Send to existing deluge process 

                port = int(open(socket, "r").readline()) 

                self.factory = ClientFactory() 

                self.factory.args = args 

                self.factory.protocol = IPCProtocolClient 

                reactor.connectTCP("127.0.0.1", port, self.factory) 

                reactor.run() 

                sys.exit(0) 

        else: 

            # Find and remove any restart tempfiles 

            old_tempfile = glob(os.path.join(ipc_dir, 'tmp*deluge')) 

            for f in old_tempfile: 

                os.remove(f) 

            lockfile = socket + ".lock" 

            log.debug("Checking if lockfile exists: %s", lockfile) 

            if os.path.lexists(lockfile) or os.path.lexists(socket): 

                try: 

                    os.kill(int(os.readlink(lockfile)), 0) 

                except OSError: 

                    log.debug("Removing lockfile since it's stale.") 

                    try: 

                        os.remove(lockfile) 

                    except OSError as ex: 

                        log.error("Failed to delete IPC lockfile file: %s", ex) 

                    try: 

                        os.remove(socket) 

                    except OSError as ex: 

                        log.error("Failed to delete IPC socket file: %s", ex) 

            try: 

                self.factory = Factory() 

                self.factory.protocol = IPCProtocolServer 

                reactor.listenUNIX(socket, self.factory, wantPID=True) 

            except twisted.internet.error.CannotListenError as ex: 

                log.info("Deluge is already running! Sending arguments to running instance...") 

                self.factory = IPCClientFactory() 

                self.factory.args = args 

                reactor.connectUNIX(socket, self.factory, checkPID=True) 

                reactor.run() 

                if self.factory.stop: 

                    log.info("Success sending arguments to running Deluge.") 

                    import gtk 

                    gtk.gdk.notify_startup_complete() 

                    sys.exit(0) 

                else: 

                    if old_tempfile: 

                        log.error("Deluge restart failed: %s", ex) 

                        sys.exit(1) 

                    else: 

                        log.warning('Restarting Deluge... (%s)', ex) 

                        # Create a tempfile to keep track of restart 

                        mkstemp('deluge', dir=ipc_dir) 

                        os.execv(sys.argv[0], sys.argv) 

            else: 

                process_args(args) 

 

    def shutdown(self): 

        if windows_check(): 

            import win32api 

            win32api.CloseHandle(self.mutex) 

 

 

def process_args(args): 

    """Process arguments sent to already running Deluge""" 

    # Make sure args is a list 

    args = list(args) 

    log.debug("Processing args from other process: %s", args) 

    if not client.connected(): 

        # We're not connected so add these to the queue 

        log.debug("Not connected to host.. Adding to queue.") 

        component.get("QueuedTorrents").add_to_queue(args) 

        return 

    config = ConfigManager("gtkui.conf") 

 

    for arg in args: 

        if not arg.strip(): 

            continue 

        log.debug("arg: %s", arg) 

 

        if is_url(arg): 

            log.debug("Attempting to add url (%s) from external source...", arg) 

            if config["interactive_add"]: 

                component.get("AddTorrentDialog").add_from_url(arg) 

                component.get("AddTorrentDialog").show(config["focus_add_dialog"]) 

            else: 

                client.core.add_torrent_url(arg, None) 

 

        elif is_magnet(arg): 

            log.debug("Attempting to add magnet (%s) from external source...", arg) 

            if config["interactive_add"]: 

                component.get("AddTorrentDialog").add_from_magnets([arg]) 

                component.get("AddTorrentDialog").show(config["focus_add_dialog"]) 

            else: 

                client.core.add_torrent_magnet(arg, {}) 

 

        else: 

            log.debug("Attempting to add file (%s) from external source...", arg) 

            if urlparse(arg).scheme == "file": 

                arg = url2pathname(urlparse(arg).path) 

            path = os.path.abspath(arg) 

 

            if not os.path.exists(path): 

                log.error("No such file: %s", path) 

                continue 

 

            if config["interactive_add"]: 

                component.get("AddTorrentDialog").add_from_files([path]) 

                component.get("AddTorrentDialog").show(config["focus_add_dialog"]) 

            else: 

                client.core.add_torrent_file(os.path.split(path)[-1], 

                                             base64.encodestring(open(path, "rb").read()), None)