On Thu, Jun 27, 2013 at 01:00:24PM +0900, YAMAMOTO Takashi wrote:
>
> Signed-off-by: YAMAMOTO Takashi <[email protected]>
> ---
> bin/rpc-cli | 236
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 236 insertions(+)
> create mode 100755 bin/rpc-cli
>
> diff --git a/bin/rpc-cli b/bin/rpc-cli
> new file mode 100755
> index 0000000..211f9a1
> --- /dev/null
> +++ b/bin/rpc-cli
> @@ -0,0 +1,236 @@
> +#!/usr/bin/env python
> +#
> +# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
> +# Copyright (C) 2013 YAMAMOTO Takashi <yamamoto at valinux co jp>
> +#
> +# Licensed under the Apache License, Version 2.0 (the "License");
> +# you may not use this file except in compliance with the License.
> +# You may obtain a copy of the License at
> +#
> +# http://www.apache.org/licenses/LICENSE-2.0
> +#
> +# Unless required by applicable law or agreed to in writing, software
> +# distributed under the License is distributed on an "AS IS" BASIS,
> +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> +# implied.
> +# See the License for the specific language governing permissions and
> +# limitations under the License.
> +
> +# a simple command line msgpack-rpc client
> +#
> +# a usage example:
> +# % PYTHONPATH=. ./bin/rpc-cli \
> +# --peers=echo-server=localhost:9999,hoge=localhost:9998
> +# (Cmd) request echo-server echo ["hoge"]
> +# RESULT hoge
> +# (Cmd) request echo-server notify ["notify-method", ["param1","param2"]]
> +# RESULT notify-method
> +# (Cmd)
> +# NOTIFICATION from echo-server ['notify-method', ['param1', 'param2']]
> +# (Cmd)
> +
> +import ryu.contrib
> +
> +from oslo.config import cfg
> +
> +import cmd
> +import signal
> +import socket
> +import sys
> +import termios
> +
> +from ryu.lib import rpc
> +
> +
> +CONF = cfg.CONF
> +CONF.register_cli_opts([
> + # eg. rpc-cli --peers=hoge=localhost:9998,fuga=localhost:9999
> + cfg.ListOpt('peers', default=[], help='list of peers')
> +])
> +
> +
> +class Peer(object):
> + def __init__(self, name, addr):
> + self._name = name
> + self._addr = addr
> + self.client = None
> + try:
> + self.connect()
> + except:
> + pass
> +
> + def connect(self):
> + self.client = None
> + s = socket.create_connection(self._addr)
> + self.client = rpc.Client(s, notification_callback=self.notification)
> +
> + def try_to_connect(self, verbose=False):
> + if self.client:
> + return
> + try:
> + self.connect()
> + assert self.client
> + except Exception, e:
> + if verbose:
> + print "connection failure", e
> + raise EOFError
> +
> + def notification(self, n):
> + print "NOTIFICATION from", self._name, n
> +
> + def call(self, method, params):
> + return self._do(lambda: self.client.call(method, params))
> +
> + def send_notification(self, method, params):
> + self._do(lambda: self.client.send_notification(method, params))
> +
> + def _do(self, f):
> + def g():
> + try:
> + return f()
> + except EOFError:
> + self.client = None
> + raise
> +
> + self.try_to_connect(verbose=True)
> + try:
> + return g()
> + except EOFError:
> + print "disconnected. trying to connect..."
> + self.try_to_connect(verbose=True)
> + print "connected. retrying the request..."
> + return g()
> +
> +
> +peers = {}
> +
> +
> +def add_peer(name, host, port):
> + peers[name] = Peer(name, (host, port))
> +
> +
> +class Cmd(cmd.Cmd):
> + def __init__(self, *args, **kwargs):
> + self._in_onecmd = False
> + self._notification_check_interval = 1 # worth to be configurable?
> + cmd.Cmd.__init__(self, *args, **kwargs)
> +
> + def _request(self, line, f):
> + args = line.split(None, 2)
> + try:
> + peer = args[0]
> + method = args[1]
> + params = eval(args[2])
> + except:
> + print "argument error"
> + return
> + try:
> + p = peers[peer]
> + except KeyError:
> + print "unknown peer", peer
> + return
> + try:
> + f(p, method, params)
> + except rpc.RPCError, e:
> + print "RPC ERROR", e
> + except EOFError:
> + print "disconnected"
> +
> + def _complete_peer(self, text, line, begidx, endidx):
> + if len((line + 'x').split()) >= 3:
> + return []
> + return [name for name in peers if name.startswith(text)]
> +
> + def do_request(self, line):
> + """request <peer> <method> <params>
> + send a msgpack-rpc request and print a response.
> + <params> is a python code snippet, it should be eval'ed to a list.
> + """
> +
> + def f(p, method, params):
> + result = p.call(method, params)
> + print "RESULT", result
> +
> + self._request(line, f)
> +
> + def do_notify(self, line):
> + """notify <peer> <method> <params>
> + send a msgpack-rpc notification.
> + <params> is a python code snippet, it should be eval'ed to a list.
> + """
> +
> + def f(p, method, params):
> + p.send_notification(method, params)
> +
> + self._request(line, f)
> +
> + def complete_request(self, text, line, begidx, endidx):
> + return self._complete_peer(text, line, begidx, endidx)
> +
> + def complete_notify(self, text, line, begidx, endidx):
> + return self._complete_peer(text, line, begidx, endidx)
> +
> + def do_EOF(self, line):
> + sys.exit(0)
> +
> + def emptyline(self):
> + self._peek_notification()
> +
> + def preloop(self):
> + self._peek_notification()
preloop method is defined twice.
> +
> + def _peek_notification(self):
> + for k, p in peers.iteritems():
> + if p.client:
> + try:
> + p.client.peek_notification()
> + except EOFError:
> + p.client = None
> + print "disconnected", p._name
> +
> + @staticmethod
> + def _save_termios():
> + return termios.tcgetattr(sys.stdin.fileno())
> +
> + @staticmethod
> + def _restore_termios(t):
> + termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, t)
> +
> + def preloop(self):
> + self._saved_termios = self._save_termios()
> + signal.signal(signal.SIGALRM, self._timeout)
> + signal.alarm(1)
> +
> + def onecmd(self, str):
> + self._in_onecmd = True
> + try:
> + return cmd.Cmd.onecmd(self, str)
> + finally:
> + self._in_onecmd = False
> +
> + def _timeout(self, sig, frame):
> + if not self._in_onecmd:
> + # restore terminal settings. (cooked/raw, ...)
> + # required for pypy at least.
> + # this doesn't seem to be needed for cpython readline
> + # module but i'm not sure if it's by spec or luck.
> + o = self._save_termios()
> + self._restore_termios(self._saved_termios)
> + self._peek_notification()
> + self._restore_termios(o)
> + signal.alarm(self._notification_check_interval)
> +
> +
> +def main():
> + CONF(project='rpc-cli', version='rpc-cli')
> +
> + for p_str in CONF.peers:
> + name, addr = p_str.split('=')
> + host, port = addr.rsplit(':', 1)
> + add_peer(name, host, port)
> +
> + Cmd().cmdloop()
> +
> +
> +if __name__ == "__main__":
> + main()
> --
> 1.8.1.5
>
>
> ------------------------------------------------------------------------------
> This SF.net email is sponsored by Windows:
>
> Build for Windows Store.
>
> http://p.sf.net/sfu/windows-dev2dev
> _______________________________________________
> Ryu-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/ryu-devel
>
--
yamahata
------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:
Build for Windows Store.
http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel