Permalink
Browse files

Service scaffolding ported from Drift

  • Loading branch information...
brendonh committed Aug 25, 2012
1 parent d6c0833 commit c9d68aadc3872c0dca0921dfecd8d71566eecd46
View
@@ -0,0 +1 @@
+pkg
View
@@ -0,0 +1,3 @@
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+export GOPATH=$DIR
+export PATH=$PATH:$GOPATH/bin
View
@@ -0,0 +1,88 @@
+package goservice
+
+import (
+ "fmt"
+ "container/list"
+)
+
+func Parse(argspec []APIArg, args APIData) (
+ bool, *list.List, APIData) {
+
+ var parsedArgs APIData = make(APIData);
+ var errors = list.New()
+
+ for _, arg := range argspec {
+
+ givenVal, ok := args[arg.Name]
+ if !ok {
+ if arg.Default != nil {
+ parsedArgs[arg.Name] = arg.Default
+ } else {
+ errors.PushBack(fmt.Sprintf(
+ "Missing argument: %s (%s)",
+ arg.Name, stringArgType(arg.ArgType)))
+ }
+ continue
+ }
+
+ ok, conversionErrors, val := convertArgVal(arg, givenVal)
+
+ if !ok {
+ if conversionErrors != nil {
+ for e := conversionErrors.Front(); e != nil; e = e.Next() {
+ errors.PushBack(fmt.Sprintf(
+ "In %s: %s", arg.Name, e.Value))
+ }
+ } else {
+ errors.PushBack(fmt.Sprintf(
+ "Invalid value for %s (expected %s): %v",
+ arg.Name, stringArgType(arg.ArgType), givenVal))
+ }
+ continue
+ }
+
+ parsedArgs[arg.Name] = val
+ }
+
+ if (errors.Len() > 0) {
+ return false, errors, nil
+ }
+
+ return true, nil, parsedArgs
+}
+
+
+func convertArgVal(arg APIArg, val interface{}) (
+ bool, *list.List, interface{}) {
+ defer func() {
+ recover()
+ }()
+ switch arg.ArgType {
+ case IntArg:
+ var floatval float64 = val.(float64)
+ return true, nil, int(floatval);
+ case FloatArg:
+ return true, nil, val.(float64)
+ case StringArg:
+ return true, nil, val.(string)
+ case NestedArg:
+ spec := arg.Extra.([]APIArg)
+ nest := val.(APIData)
+ return Parse(spec, nest)
+ case RawArg:
+ return true, nil, val
+ }
+ return false, nil, nil
+}
+
+
+func stringArgType(argType int) string {
+ switch argType {
+ case IntArg: return "int"
+ case FloatArg: return "float"
+ case StringArg: return "string"
+ case NestedArg: return "nested"
+ case RawArg: return "raw"
+ }
+ return "unknown"
+}
View
@@ -0,0 +1,96 @@
+package goservice
+
+import (
+ "fmt"
+ "net"
+ "net/http"
+ "strings"
+ "strconv"
+ "encoding/json"
+)
+
+type HttpRpcEndpoint struct {
+ Address string
+ listener net.Listener
+ context ServerContext
+}
+
+
+func NewHttpRpcEndpoint(address string, context ServerContext) Endpoint {
+ return &HttpRpcEndpoint{
+ Address: address,
+ context: context,
+ }
+}
+
+func (endpoint *HttpRpcEndpoint) Start() bool {
+ if endpoint.listener != nil {
+ return false
+ }
+
+ listener, error := net.Listen("tcp", endpoint.Address)
+ if error != nil {
+ fmt.Printf("Error starting HTTP RPC endpoint: %v\n", error)
+ return false
+ }
+
+ endpoint.listener = listener
+
+ mux := http.NewServeMux()
+ mux.HandleFunc("/favicon.ico", http.NotFound)
+ mux.Handle("/", endpoint)
+ go http.Serve(listener, mux)
+
+ fmt.Printf("HTTP endpoint started at %s\n", endpoint.Address)
+
+ return true
+}
+
+
+func (endpoint *HttpRpcEndpoint) Stop() bool {
+ if endpoint.listener == nil {
+ return true
+ }
+
+ if error := endpoint.listener.Close(); error != nil {
+ fmt.Printf("Error stopping HTTP RPC endpoint: %v\n", error)
+ return false
+ }
+
+ endpoint.listener = nil
+ return true
+}
+
+
+func (endpoint *HttpRpcEndpoint) ServeHTTP(response http.ResponseWriter, req *http.Request) {
+ bits := strings.SplitN(req.URL.Path[1:], "/", 2)
+
+ if len(bits) != 2 {
+ http.NotFound(response, req)
+ return
+ }
+
+ req.ParseForm()
+
+ var form = make(APIData)
+ for k, v := range req.Form {
+ form[k] = v[0]
+ }
+
+ // XXX TODO: Session tracking
+ var session = NewSession()
+
+ ok, errors, resp := endpoint.context.API().HandleCall(
+ bits[0], bits[1], form, session, endpoint.context)
+
+ if errors != nil {
+ response.WriteHeader(400)
+ }
+
+ response.Header().Add("Content-Type", "text/plain")
+
+ jsonReply, _ := json.Marshal(Response(ok, errors, resp))
+ response.Header().Add("Content-Length", strconv.Itoa(len(jsonReply)))
+
+ response.Write(jsonReply)
+}
View
@@ -0,0 +1,44 @@
+package goservice
+
+import (
+ "os"
+)
+
+type Server struct {
+ services API
+ endpoints []Endpoint
+
+ stopper chan os.Signal
+}
+
+func NewServer(services API) *Server {
+ return &Server {
+ services: services,
+ endpoints: make([]Endpoint, 0),
+ }
+}
+
+func (server *Server) AddEndpoint(endpoint Endpoint) {
+ server.endpoints = append(server.endpoints, endpoint)
+}
+
+func (server *Server) Start() {
+ for _, endpoint := range server.endpoints {
+ endpoint.Start()
+ }
+}
+
+func (server *Server) Stop() {
+ for _, endpoint := range server.endpoints {
+ endpoint.Stop()
+ }
+}
+
+
+// ------------------------------------------
+// Context API
+// ------------------------------------------
+
+func (server *Server) API() API {
+ return server.services
+}
Oops, something went wrong.

0 comments on commit c9d68aa

Please sign in to comment.