Commits

sungo  committed c04e333

mod to add support for pyjamas jsonrpc calls

  • Participants
  • Parent commits 8eaf358

Comments (0)

Files changed (4)

File JSONRPCExample.py

+import pyjd # dummy in pyjs
+
+from pyjamas.ui.RootPanel import RootPanel
+from pyjamas.ui.TextArea import TextArea
+from pyjamas.ui.Label import Label
+from pyjamas.ui.Button import Button
+from pyjamas.ui.HTML import HTML
+from pyjamas.ui.VerticalPanel import VerticalPanel
+from pyjamas.ui.HorizontalPanel import HorizontalPanel
+from pyjamas.ui.ListBox import ListBox
+from pyjamas.JSONService import JSONProxy
+
+class JSONRPCExample:
+    def onModuleLoad(self):
+        self.TEXT_WAITING = "Waiting for response..."
+        self.TEXT_ERROR = "Server Error"
+        self.METHOD_ECHO = "Echo"
+        self.METHOD_REVERSE = "Reverse"
+        self.METHOD_UPPERCASE = "UPPERCASE"
+        self.METHOD_LOWERCASE = "lowercase"
+        self.METHOD_NONEXISTANT = "Non existant"
+        self.methods = [self.METHOD_ECHO, self.METHOD_REVERSE, 
+                        self.METHOD_UPPERCASE, self.METHOD_LOWERCASE, 
+                        self.METHOD_NONEXISTANT]
+
+        self.remote_go = GoRpc()
+
+        self.status=Label()
+        self.text_area = TextArea()
+        self.text_area.setText("""{'Test'} [\"String\"]
+\tTest Tab
+Test Newline\n
+after newline
+""" + r"""Literal String:
+{'Test'} [\"String\"]
+""")
+        self.text_area.setCharacterWidth(80)
+        self.text_area.setVisibleLines(8)
+        
+        self.method_list = ListBox()
+        self.method_list.setName("hello")
+        self.method_list.setVisibleItemCount(1)
+        for method in self.methods:
+            self.method_list.addItem(method)
+        self.method_list.setSelectedIndex(0)
+
+        method_panel = HorizontalPanel()
+        method_panel.add(HTML("Remote string method to call: "))
+        method_panel.add(self.method_list)
+        method_panel.setSpacing(8)
+
+        self.button_go = Button("Send to GO Service", self)
+
+        buttons = HorizontalPanel()
+        buttons.add(self.button_go)
+        buttons.setSpacing(8)
+        
+        info = """<h2>JSON-RPC Example</h2>
+        <p>This example demonstrates the calling of server services with
+           <a href="http://json-rpc.org/">JSON-RPC</a>.
+        </p>
+        <p>Enter some text below, and press a button to send the text
+           to an Echo service on your server. An echo service simply sends the exact same text back that it receives.
+           </p>"""
+        
+        panel = VerticalPanel()
+        panel.add(HTML(info))
+        panel.add(self.text_area)
+        panel.add(method_panel)
+        panel.add(buttons)
+        panel.add(self.status)
+        
+        RootPanel().add(panel)
+
+    def onClick(self, sender):
+        self.status.setText(self.TEXT_WAITING)
+        method = self.methods[self.method_list.getSelectedIndex()]
+        text = self.text_area.getText()
+
+        # demonstrate proxy & callMethod()
+        if sender == self.button_go:
+            if method == self.METHOD_ECHO:
+                id = self.remote_go.echo(text, self)
+            elif method == self.METHOD_REVERSE:
+                id = self.remote_go.callMethod("reverse", [text], self)
+            elif method == self.METHOD_UPPERCASE:
+                id = self.remote_go.uppercase(text, self)
+            elif method == self.METHOD_LOWERCASE:
+                id = self.remote_go.lowercase(self, msg=text)
+            elif method == self.METHOD_NONEXISTANT:
+                id = self.remote_go.nonexistant(text, self)
+
+    def onRemoteResponse(self, response, request_info):
+        self.status.setText(response)
+
+    def onRemoteError(self, code, errobj, request_info):
+        # onRemoteError gets the HTTP error code or 0 and
+        # errobj is an jsonrpc 2.0 error dict:
+        #     {
+        #       'code': jsonrpc-error-code (integer) ,
+        #       'message': jsonrpc-error-message (string) ,
+        #       'data' : extra-error-data
+        #     }
+        message = errobj['message']
+        if code != 0:
+            self.status.setText("HTTP error %d: %s" % 
+                                (code, message))
+        else:
+            code = errobj['code']
+            self.status.setText("JSONRPC Error %s: %s" %
+                                (code, message))
+
+
+
+class GoRpc(JSONProxy):
+    def __init__(self):
+        JSONProxy.__init__(self, "/post", ["echo", "reverse", "uppercase", "lowercase", "nonexistant"])
+
+if __name__ == '__main__':
+    # for pyjd, set up a web server and load the HTML from there:
+    # this convinces the browser engine that the AJAX will be loaded
+    # from the same URI base as the URL, it's all a bit messy...
+    pyjd.setup("http://127.0.0.1/examples/jsonrpc/public/JSONRPCExample.html")
+    app = JSONRPCExample()
+    app.onModuleLoad()
+    pyjd.run()
+
 GOFILES=http_jsonrpc.go
 
 include $(GOROOT)/src/Make.pkg
+
+web:test.go install
+	$(GC) test.go
+	8l -o test test.8

File http_jsonrpc.go

 	"reflect"
 	"sync"
 	"strconv"
+	"log"
 )
 
 type result struct {
 	Result interface{} "result"
-	Id int "id"
-	Error interface{} "error"
+	Id     int         "id"
+	Error  interface{} "error"
 }
 
-func (s *Server)Register(name string, function interface{}) {
+func (s *Server) Register(name string, function interface{}) {
 	v := reflect.NewValue(function)
-	vf:= v.(*reflect.FuncValue)
+	vf := v.(*reflect.FuncValue)
 	t := v.Type().(*reflect.FuncType)
-	if t==nil {
+	if t == nil {
 		panic("http_jsonrpc.Register: Cannot reflect function")
 	}
 	olen := t.NumOut()
-	if olen>2 {
+	if olen > 2 {
 		panic("http_jsonrpc.Register: Function must return 0-2 results")
 	}
 
 	buf := new(bytes.Buffer)
-	fmt.Fprintf(buf,`  {"name":"%s",`,name)
+	fmt.Fprintf(buf, `  {"name":"%s",`, name)
 	buf.WriteString(`
    "parameters":[
 `)
 	l := t.NumIn()
-	for i:=0; i<l; i++ {
-		fmt.Fprintf(buf, `    {"name": "p%d", "type":%s}`,i,t2json(t.In(i)))
-		if i+1<l {
+	for i := 0; i < l; i++ {
+		fmt.Fprintf(buf, `    {"name": "p%d", "type":%s}`, i, t2json(t.In(i)))
+		if i+1 < l {
 			buf.WriteString(",\n")
 		}
 	}
 	buf.WriteString("}")
 
 	f := func(r *http.Request, w http.ResponseWriter, id int, params []interface{}) {
-		fmt.Printf("Handler %s called\n",name)
+		fmt.Printf("Handler %s called\n", name)
 		ps := make([]reflect.Value, len(params))
-		for i:=0; i<len(params); i++ {
+		for i := 0; i < len(params); i++ {
 			ps[i] = tfit(t.In(i), params[i])
-			fmt.Printf("P%d = %v %v\n",i,ps[i].Interface(),ps[i].Type())
+			fmt.Printf("P%d = %v %v\n", i, ps[i].Interface(), ps[i].Type())
 		}
 		rs := vf.Call(ps)
 		var buf bytes.Buffer
 		enc := json.NewEncoder(&buf)
-		
+
 		if len(rs) == 0 {
-			enc.Encode(result{"",id,nil})
+			enc.Encode(result{"", id, nil})
 		} else if len(rs) == 1 || rs[1].Interface() == nil {
-			enc.Encode(result{rs[0].Interface(),id,nil})
+			enc.Encode(result{rs[0].Interface(), id, nil})
 		} else {
-			enc.Encode(result{nil,id,rs[1].Interface()})
+			enc.Encode(result{nil, id, rs[1].Interface()})
 		}
-		fmt.Printf(" => %s",buf.Bytes())
+		fmt.Printf(" => %s", buf.Bytes())
 		w.SetHeader("Content-Type", "application/json")
 		w.Write(buf.Bytes())
 	}
-	
+
 	s.Lock()
 	s.ds[name] = buf.Bytes()
 	s.hs[name] = f
 func tfit(ty reflect.Type, val interface{}) reflect.Value {
 	switch ty := ty.(type) {
 	case *reflect.IntType:
-		if s,sok := val.(string); sok {
-			i,_ := strconv.Atoi(s)
+		if s, sok := val.(string); sok {
+			i, _ := strconv.Atoi(s)
 			return reflect.NewValue(i)
-		} else if s,sok := val.(float64); sok {
+		} else if s, sok := val.(float64); sok {
 			return reflect.NewValue(int(s))
 		}
 	}
 }
 
 func t2json(t reflect.Type) string {
-	switch t:=t.(type) {
+	switch t := t.(type) {
 	case *reflect.IntType:
 		return `"INTEGER"`
 	case *reflect.StringType:
 	return `"STRING"`
 }
 
-type handler func(*http.Request,http.ResponseWriter, int, []interface{})
+type handler func(*http.Request, http.ResponseWriter, int, []interface{})
 
 type Server struct {
 	sync.Mutex
 	s := &Server{}
 	s.hs = map[string]handler{}
 	s.ds = map[string][]byte{}
-		return s
+	return s
 }
 
-	
 
-func (s *Server)ServeHTTP(w http.ResponseWriter, r *http.Request) {
-		fmt.Printf("ServeHTTP called with %s\n",r.Method)
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	fmt.Printf("ServeHTTP called with %s\n", r.Method)
 	switch r.Method {
 	case "GET":
-		outputSMD(s,r,w)
+		outputSMD(s, r, w)
 	case "POST":
+		fmt.Printf("Post body is:\t%v\n", r.Body)
 		dec := json.NewDecoder(r.Body)
 		var m map[string]interface{}
 		err := dec.Decode(&m)
-		if err!=nil {
+		if err != nil {
+			log.Println("Decode Error!")
 			return
 		}
 
-		rawid,idok := m["id"]
-		if !idok { return }
-		rid,idok := rawid.(float64)
-		if !idok { return }
+		fmt.Printf("after decode is: %v\n", m)
+		rawid, idok := m["id"]
+		if !idok {
+			log.Println("raw id Error!")
+		}
+		rid, idok := rawid.(float64)
+		if !idok {
+			log.Println("id Error!", rawid.(string)[2:], rawid)
+			rid, _ = strconv.Atof64(rawid.(string)[2:])
+		}
 		id := int(rid)
 
-		rawme,meok := m["method"]
-		if !meok { return }
-		me,meok := rawme.(string)
-		if !meok { return }
+		rawme, meok := m["method"]
+		if !meok {
+			log.Println("rawme Error!")
+		}
+		me, meok := rawme.(string)
+		if !meok {
+			log.Println("me Error!")
+		}
 
-		rawpa,paok := m["params"]
-		if !paok { return }
-		pa,paok := rawpa.([]interface{})
-		if !paok { return }
+		rawpa, paok := m["params"]
+		if !paok {
+			log.Println("rawpa Error!")
+		}
+		pa, paok := rawpa.([]interface{})
+		if !paok {
+			log.Println("pa Error!")
+		}
 
 		s.Lock()
 		f := s.hs[me]
 		s.Unlock()
-		if m!=nil {
-			f(r,w,id,pa)
+		if m != nil {
+			f(r, w, id, pa)
 		}
 
-		fmt.Printf("%v\n",m)	
+		fmt.Printf("%v\n", m)
 	}
-	
+
 }
 
 func outputSMD(s *Server, r *http.Request, w http.ResponseWriter) {
 
 	i := 0
 	l := len(s.ds)
-	for _,v := range s.ds {
+	for _, v := range s.ds {
 		buf.Write(v)
 		i++
-		if i<l {
+		if i < l {
 			buf.WriteString(",\n")
 		}
 	}
 
 	s.Unlock()
 
-	
 	buf.Write([]byte(`]
 }
 `))
 	w.SetHeader("Content-Type", "text/plain")
 	w.Write(buf.Bytes())
 }
-
-
+package main
+
+import (
+	"bitbucket.org/taruti/http_jsonrpc.go"
+	"http"
+	"os"
+	"strings"
+)
+
+func add(a int, b int) int {
+	return a + b
+}
+func echo(s string) string {
+	return s
+}
+func reverse(s string) string {
+	return s
+}
+func lowercase(s string) string {
+	return strings.ToLower(s)
+}
+func uppercase(s string) string {
+	return strings.ToUpper(s)
+}
+func negate(a int) (int, os.Error) {
+	if a == 0 {
+		return 0, os.NewError("Zero!")
+	}
+	return -a, nil
+}
+
+func index(w http.ResponseWriter, r *http.Request) {
+	w.Write([]byte(`
+<!DOCTYPE HTML>
+<html>
+<title>test</title>
+<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js"
+		djConfig="parseOnLoad: true, isDebug: true"
+		type="text/javascript"></script>
+<script type="text/javascript">
+dojo.require('dojo.rpc.JsonService');
+function setup() {
+var smdURL = '/post';
+srv = new dojo.rpc.JsonService(smdURL);
+}
+
+function doCalc() {
+console.log(srv)
+srv.add(document.getElementById('a').value, document.getElementById('b').value).addCallback(doCalcCallback);
+srv.negate(document.getElementById('a').value).addCallback(doCalcCallback);
+}
+
+function doCalcCallback(result) {
+alert(result);
+}
+
+dojo.addOnLoad(setup);
+</script>
+<body>
+
+<fieldset>
+  <legend>Simple JSON-RPC example</legend>
+  A: <input type="text" id="a" size="3"/> B: <input type="text" id="b" size="3"/><br/>
+  <input type="button" onclick="doCalc();" value="A+B"/>
+</fieldset>
+
+HTML from http://examples.stubbles.net/docroot/json-rpc/dojo.php
+</body>
+</html>
+`))
+}
+
+func main() {
+	s := http_jsonrpc.New()
+	s.Register("add", add)
+	s.Register("negate", negate)
+	s.Register("echo",echo)
+	s.Register("reverse",reverse)
+	s.Register("uppercase",uppercase) 
+	s.Register("lowercase",lowercase)
+	http.Handle("/post", s)
+	http.HandleFunc("/index", index)
+	http.Handle("/index.html", http.RedirectHandler("/JSONRPCExample.html", 200))
+	http.Handle("/", http.FileServer("output", ""))
+	http.ListenAndServe(":1234", nil)
+}