]> gitweb.factorcode.org Git - factor.git/blob - basis/xml-rpc/xml-rpc.factor
Fixing failing unit tests in compiler.tree.propagation due to constraints
[factor.git] / basis / xml-rpc / xml-rpc.factor
1 ! Copyright (C) 2005, 2009 Daniel Ehrenberg
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors kernel xml arrays math generic http.client
4 combinators hashtables namespaces io base64 sequences strings
5 calendar xml.data xml.writer xml.traversal assocs math.parser
6 debugger calendar.format math.order xml.syntax ;
7 IN: xml-rpc
8
9 ! * Sending RPC requests
10 ! TODO: time
11 ! The word for what this does is "serialization"! Wow!
12
13 GENERIC: item>xml ( object -- xml )
14
15 M: integer item>xml
16     dup 31 2^ neg 31 2^ 1 - between?
17     [ "Integers must fit in 32 bits" throw ] unless
18     [XML <i4><-></i4> XML] ;
19
20 UNION: boolean t POSTPONE: f ;
21
22 M: boolean item>xml
23     "1" "0" ? [XML <boolean><-></boolean> XML] ;
24
25 M: float item>xml
26     number>string [XML <double><-></double> XML] ;
27
28 M: string item>xml
29     [XML <string><-></string> XML] ;
30
31 : struct-member ( name value -- tag )
32     over string? [ "Struct member name must be string" throw ] unless
33     item>xml
34     [XML
35         <member>
36             <name><-></name>
37             <value><-></value>
38         </member>
39     XML] ;
40
41 M: hashtable item>xml
42     [ struct-member ] { } assoc>map
43     [XML <struct><-></struct> XML] ;
44
45 M: array item>xml
46     [ item>xml [XML <value><-></value> XML] ] map
47     [XML <array><data><-></data></array> XML] ;
48
49 TUPLE: base64 string ;
50
51 C: <base64> base64
52
53 M: base64 item>xml
54     string>> >base64
55     [XML <base64><-></base64> XML] ;
56
57 : params ( seq -- xml )
58     [ item>xml [XML <param><value><-></value></param> XML] ] map
59     [XML <params><-></params> XML] ;
60
61 : method-call ( name seq -- xml )
62     params
63     <XML
64         <methodCall>
65             <methodName><-></methodName>
66             <->
67         </methodCall>
68     XML> ;
69
70 : return-params ( seq -- xml )
71     params <XML <methodResponse><-></methodResponse> XML> ;
72
73 : return-fault ( fault-code fault-string -- xml )
74     [ "faultString" set "faultCode" set ] H{ } make-assoc item>xml
75     <XML
76         <methodResponse>
77             <fault>
78                 <value><-></value>
79             </fault>
80         </methodResponse>
81     XML> ;
82
83 TUPLE: rpc-method name params ;
84
85 C: <rpc-method> rpc-method
86
87 TUPLE: rpc-response params ;
88
89 C: <rpc-response> rpc-response
90
91 TUPLE: rpc-fault code string ;
92
93 C: <rpc-fault> rpc-fault
94
95 GENERIC: send-rpc ( rpc -- xml )
96 M: rpc-method send-rpc
97     [ name>> ] [ params>> ] bi method-call ;
98 M: rpc-response send-rpc
99     params>> return-params ;
100 M: rpc-fault send-rpc
101     [ code>> ] [ string>> ] bi return-fault ;
102
103 ! * Recieving RPC requests
104 ! this needs to have much better error checking
105
106 TUPLE: server-error tag message ;
107
108 : server-error ( tag message -- * )
109     \ server-error boa throw ;
110
111 M: server-error error.
112     "Error in XML supplied to server" print
113     "Description: " write dup message>> print
114     "Tag: " write tag>> xml>string print ;
115
116 TAGS: xml>item ( tag -- object )
117
118 TAG: string xml>item
119     children>string ;
120
121 : children>number ( tag -- n )
122     children>string string>number ;
123
124 TAG: i4 xml>item children>number ;
125 TAG: int xml>item children>number ;
126 TAG: double xml>item children>number ;
127
128 TAG: boolean xml>item
129     children>string {
130         { "1" [ t ] }
131         { "0" [ f ] }
132         [ "Bad boolean" server-error ]
133     } case ;
134
135 : unstruct-member ( tag -- )
136     children-tags first2
137     first-child-tag xml>item
138     [ children>string ] dip swap set ;
139
140 TAG: struct xml>item
141     [
142         children-tags [ unstruct-member ] each
143     ] H{ } make-assoc ;
144
145 TAG: base64 xml>item
146     children>string base64> <base64> ;
147
148 TAG: array xml>item
149     first-child-tag children-tags
150     [ first-child-tag xml>item ] map ;
151
152 : params>array ( tag -- array )
153     children-tags
154     [ first-child-tag first-child-tag xml>item ] map ;
155
156 : parse-rpc-response ( xml -- array )
157     first-child-tag params>array ;
158
159 : parse-method ( xml -- string array )
160     children-tags first2
161     [ children>string ] [ params>array ] bi* ;
162
163 : parse-fault ( xml -- fault-code fault-string )
164     first-child-tag first-child-tag first-child-tag
165     xml>item [ "faultCode" get "faultString" get ] bind ;
166
167 : receive-rpc ( xml -- rpc )
168     dup main>> dup "methodCall" =
169     [ drop parse-method <rpc-method> ] [
170         "methodResponse" = [
171             dup first-child-tag main>> "fault" =
172             [ parse-fault <rpc-fault> ]
173             [ parse-rpc-response <rpc-response> ] if
174         ] [ "Bad main tag name" server-error ] if
175     ] if ;
176
177 : post-rpc ( rpc url -- rpc )
178     ! This needs to do something in the event of an error
179     [ send-rpc ] dip http-post nip string>xml receive-rpc ;
180
181 : invoke-method ( params method url -- response )
182     [ swap <rpc-method> ] dip post-rpc ;