jsonrpc2 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/jsonrpc2 ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems" # ruby1.9 doesn't "require" it though
3
+ require "thor"
4
+ require 'jsonrpc2/client'
5
+ require 'json'
6
+ require 'pp'
7
+
8
+ class JSONClient < Thor
9
+ method_option :user, :type => :string
10
+ method_option :pass, :type => :string
11
+ desc "call URI METHOD [PARAMS]", "Call "
12
+ def call uri, method, params=nil
13
+ STDOUT << "#{uri}##{method}(#{params})"
14
+ uri = "http://#{uri}" unless uri =~ %r'://'
15
+
16
+ client = JSONRPC2::Client.new(uri, options)
17
+ STDOUT << " => "
18
+ begin
19
+ pp client.call(method, JSON.parse(params))
20
+ rescue JSONRPC2::RemoteAuthError => e
21
+ puts "ERR\nFAIL: #{e.message}"
22
+ rescue JSONRPC2::RemoteError => e
23
+ puts "ERR\nFAIL: #{e.message}"
24
+ end
25
+ end
26
+ end
27
+
28
+ JSONClient.start
data/example/config.ru CHANGED
@@ -4,15 +4,15 @@ require 'jsonrpc2/interface'
4
4
  class ::Object::Calculator < JSONRPC2::Interface
5
5
  title "JSON-RPC2 Calculator"
6
6
  introduction "This interface allows basic maths calculations via JSON-RPC2"
7
- auth_with JSONRPC2::BasicAuth.new({'user' => 'secretword'})
7
+ auth_with JSONRPC2::BasicAuth.new({'user' => 'secretword', 'admin' => 'password'})
8
8
 
9
9
  section 'Simple Ops' do
10
10
  desc 'Multiply two numbers'
11
11
  param 'a', 'Number', 'a'
12
12
  param 'b', 'Number', 'b'
13
13
  result 'Number', 'a * b'
14
- def mul args
15
- args['a'] * args['b']
14
+ def mul
15
+ params['a'] * params['b']
16
16
  end
17
17
 
18
18
  desc 'Add numbers'
@@ -22,9 +22,12 @@ class ::Object::Calculator < JSONRPC2::Interface
22
22
  param 'b', 'Number', 'Second number'
23
23
  optional 'c', 'Number', 'Third number'
24
24
  result 'Number', 'a + b + c'
25
- def sum args
26
- val = args['a'] + args['b']
27
- val += args['c'] if args['c']
25
+ def sum
26
+ val = params['a'] + params['b']
27
+ val += params['c'] if params['c']
28
+
29
+ return 42 if auth == 'admin'
30
+
28
31
  val
29
32
  end
30
33
  end
data/jsonrpc2.gemspec CHANGED
@@ -54,4 +54,5 @@ EOD
54
54
  gem.add_dependency("httpclient")
55
55
  gem.add_dependency("json")
56
56
  gem.add_dependency("RedCloth")
57
+ gem.add_dependency('thor')
57
58
  end
data/lib/jsonrpc2/auth.rb CHANGED
@@ -89,14 +89,15 @@ class BasicAuth < HttpAuth
89
89
 
90
90
  # Checks users hash and then the block given to the constructor to
91
91
  # verify username / password.
92
+ # @return [String,false] Username or nothing
92
93
  def user_valid?(user, pass)
93
94
  if @users && @users.respond_to?(:[])
94
95
  if expected = @users[user]
95
- return pass == expected
96
+ return user if pass == expected
96
97
  end
97
98
  end
98
99
  if @lookup
99
- return @lookup.call(user, pass)
100
+ return user if @lookup.call(user, pass)
100
101
  end
101
102
  false
102
103
  end
@@ -6,6 +6,10 @@ module JSONRPC2
6
6
  class RemoteError < RuntimeError
7
7
  end
8
8
 
9
+ # JSON RPC remote auth error
10
+ class RemoteAuthError < RemoteError
11
+ end
12
+
9
13
  # Simple JSONRPC client
10
14
  class Client
11
15
  # Create client object
@@ -36,8 +40,8 @@ class Client
36
40
  headers = headers.merge(options[:headers])
37
41
  end
38
42
 
39
- if options[:auth]
40
- @client.set_auth(@uri, options[:auth][:username], options[:auth][:password])
43
+ if options[:user] && options[:pass]
44
+ @client.set_auth(@uri, options[:user], options[:pass])
41
45
  end
42
46
  result = @client.post(@uri,
43
47
  { 'method' => method, 'params' => args, 'jsonrpc' => '2.0', 'id' => (@id+=1) }.to_json,
@@ -49,8 +53,17 @@ class Client
49
53
  if data.has_key?('result')
50
54
  return data['result']
51
55
  else
52
- raise RemoteError, data['error']['message']
56
+ if data['error']['code'] == -32000 && data['error']['message'] =~ /^AuthFail/
57
+ raise RemoteAuthError, data['error']['message']
58
+ else
59
+ raise RemoteError, data['error']['message']
60
+ end
53
61
  end
62
+ elsif result.status_code == 401
63
+ if result.headers['WWW-Authenticate'].to_s =~ /realm="([^"]*?)"/
64
+ suffix = " for #{$1}"
65
+ end
66
+ raise RemoteAuthError, "Authentication failed#{suffix}"
54
67
  else
55
68
  raise result.body
56
69
  end
@@ -96,23 +96,28 @@ class Interface
96
96
  end
97
97
  # JSON error helper
98
98
  def response_error(code, message, data)
99
- { 'jsonrpc' => '2.0', 'error' => { 'code' => code, 'message' => message, 'data' => data }, 'id' => @id }
99
+ { 'jsonrpc' => '2.0', 'error' => { 'code' => code, 'message' => message, 'data' => data }, 'id' => (@jsonrpc_call && @jsonrpc_call['id'] || nil) }
100
100
  end
101
+ # Params helper
102
+ def params
103
+ @jsonrpc_call['params']
104
+ end
105
+ # Auth info
106
+ def auth
107
+ @jsonrpc_auth
108
+ end
101
109
  # Check call validity and authentication & make a single method call
102
110
  #
103
111
  # @param [Hash] rpc JSON-RPC-2 call
104
112
  def dispatch_single(rpc)
105
113
  unless rpc.has_key?('id') && rpc.has_key?('method') && rpc['jsonrpc'].eql?('2.0')
106
- @id = nil
107
114
  return response_error(-32600, 'Invalid request', nil)
108
115
  end
109
- @id = rpc['id']
110
- @method = rpc['method']
111
- @rpc = rpc
112
-
116
+ @jsonrpc_call = rpc
117
+
113
118
  begin
114
- if self.class.auth_with
115
- self.class.auth_with.client_check(@env, rpc) or raise AuthFail, "Invalid credentials"
119
+ if self.class.auth_with && ! @jsonrpc_auth
120
+ (@jsonrpc_auth = self.class.auth_with.client_check(@env, rpc)) or raise AuthFail, "Invalid credentials"
116
121
  end
117
122
 
118
123
  call(rpc['method'], rpc['id'], rpc['params'])
@@ -7,19 +7,23 @@ module JSONRPC2
7
7
  def to_textile
8
8
  return nil if @about.nil? or @about.empty?
9
9
  str = ""
10
+
10
11
  if @title
11
12
  str << "h1. #{@title}\n"
12
13
  else
13
14
  str << "h1. #{name}\n"
14
15
  end
16
+
15
17
  if @introduction
16
18
  str << "\nh2. Introduction\n\n#{@introduction}\n"
17
19
  end
18
20
 
21
+ # Output type descriptions
22
+ #
19
23
  unless @types.nil? or @types.empty?
20
- str << "\nh2. Types\n"
24
+ str << "\n\nh2. Types\n"
21
25
  @types.sort_by { |k,v| k }.each do |k,type|
22
- str << "\nh5. #{k} type\n"
26
+ str << "\n\nh5. #{k} type\n"
23
27
 
24
28
  str << "\n|_. Field |_. Type |_. Required? |_. Description |"
25
29
  type.fields.each do |field|
@@ -29,27 +33,32 @@ module JSONRPC2
29
33
  end
30
34
  end
31
35
 
32
- @sections.each do |section|
33
- str << "\nh2. #{section[:name]}\n"
36
+
37
+ # Output method definitions
38
+ #
39
+ (@sections||[]).each do |section|
40
+ str << "\n\nh2. #{section[:name]}\n"
34
41
  if section[:summary]
35
42
  str << "\n#{section[:summary]}\n"
36
43
  end
37
44
 
38
45
  str += to_textile_group(section).to_s
39
46
  end
47
+
40
48
  miscfn = to_textile_group({:name => nil})
41
49
  if miscfn
42
- str << "\nh2. Misc functions\n"
50
+ str << "\n\nh2. Misc functions\n" if @sections && ! @sections.empty?
43
51
  str << miscfn
44
52
  end
53
+
45
54
  str
46
55
  end
47
56
  # Returns method description in textile
48
57
  def method_to_textile(info)
49
58
  str = ''
50
- str << "\nh3. #{info[:name]}\n"
59
+ str << "\n\nh3. #{info[:name]}\n"
51
60
  str << "\n#{info[:desc]}\n" if info[:desc]
52
- str << "\nh5. Params\n"
61
+ str << "\n\nh5. Params\n"
53
62
  if info[:params].nil?
54
63
  str << "\n* _None_\n"
55
64
  elsif info[:params].is_a?(Array)
@@ -60,17 +69,17 @@ module JSONRPC2
60
69
  end
61
70
 
62
71
  if res = info[:returns]
63
- str << "\nh5. Result\n"
72
+ str << "\n\nh5. Result\n"
64
73
  str << "\n* @#{res[:type]}@"
65
74
  str << " - #{res[:desc]}" if res[:desc]
66
75
  str << "\n"
67
76
  else
68
- str << "\nh5. Result\n"
77
+ str << "\n\nh5. Result\n"
69
78
  str << "\n* @null@"
70
79
  end
71
80
 
72
81
  if examples = info[:examples]
73
- str << "\nh5. Sample usage\n"
82
+ str << "\n\nh5. Sample usage\n"
74
83
 
75
84
  nice_json = lambda do |data|
76
85
  JSON.pretty_unparse(data).gsub(/\n\n+/,"\n").gsub(/[{]\s+[}]/m, '{ }').gsub(/\[\s+\]/m, '[ ]')
@@ -1,5 +1,5 @@
1
1
  # JSONRPC2 namespace module
2
2
  module JSONRPC2
3
3
  # Version
4
- VERSION = "0.0.4"
4
+ VERSION = "0.0.5"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonrpc2
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 4
10
- version: 0.0.4
9
+ - 5
10
+ version: 0.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Geoff Youngs
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-07-17 00:00:00 Z
18
+ date: 2012-07-19 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: httpclient
@@ -59,6 +59,20 @@ dependencies:
59
59
  version: "0"
60
60
  type: :runtime
61
61
  version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: thor
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :runtime
75
+ version_requirements: *id004
62
76
  description: |+
63
77
  == Description
64
78
 
@@ -98,8 +112,8 @@ description: |+
98
112
 
99
113
  email:
100
114
  - git@intersect-uk.co.uk
101
- executables: []
102
-
115
+ executables:
116
+ - jsonrpc2
103
117
  extensions: []
104
118
 
105
119
  extra_rdoc_files: []
@@ -109,6 +123,7 @@ files:
109
123
  - Gemfile
110
124
  - README.markdown
111
125
  - Rakefile
126
+ - bin/jsonrpc2
112
127
  - example/config.ru
113
128
  - jsonrpc2.gemspec
114
129
  - lib/jsonrpc2.rb