xmlrpc

package module
v0.0.0-...-1a82ba6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 22, 2016 License: MIT Imports: 21 Imported by: 2

README

go-xmlrpc

Warning! This project is under heavy development!!

go-xml rpc takes another path to provide parsing of xml. Instead of reflect for binding xml => go, go-xmlrpc generates code for xml parsing. It uses etree implementation and generates code directly for service methods. Isn't that nice? It's safe, fast, awesome!

Ok let's have a look at example

//go:generate xmlrpcgen --file $GOFILE HelloService
package example

/*
SearchService xml rpc service for searching in database
*/
type SearchService struct {
    Config Config
}

/*
Search service method
 */
func (h *SearchService) Search(query string, page int, isit bool) ([]string, error) {
    return []string{}, nil
}

That's pretty simple service with search method. Now run go generate and go-xmlrpc parses your service methods and generates xml parsing code directly to your methods.

Current version generates this code:

// This file is autogenerated by xmlrpcgen
// do not change it directly!

package core

import (
	"github.com/beevik/etree"
	"github.com/phonkee/go-xmlrpc"
	"strconv"
)

var (
	availableMethodsForSearchService = map[string]bool{
		"Search": true,
	}
)

/*
	MethodExists returns whether rpc method is available on service
*/
func (s *SearchService) MethodExists(method string) (ok bool) {
	_, ok = availableMethodsForSearchService[method]
	return
}

/*
	ListMethods returns list of all available methods for given service
*/
func (s *SearchService) ListMethods() []string {
	result := make([]string, 0, len(availableMethodsForSearchService))
	for key := range availableMethodsForSearchService {
		result = append(result, key)
	}
	return result
}

/*
	Dispatch dispatches method on service, do not use this method directly.
	root is params *etree.Element (actually "methodCall/params"
*/
func (s *SearchService) Dispatch(method string, root *etree.Element) (doc *etree.Document, err error) {

	// call appropriate methods
	switch method {
	case "Search":
		// Get parameters from xmlrpc request

		v_2 := root.FindElement("param[1]/value")
		if v_2 == nil {
			err = xmlrpc.Errorf(400, "could not find query")
			return
		}

		var query string
		if query, err = xmlrpc.XPathValueGetString(v_2, "query"); err != nil {
			return
		}

		v_3 := root.FindElement("param[2]/value")
		if v_3 == nil {
			err = xmlrpc.Errorf(400, "could not find page")
			return
		}

		var page int
		if page, err = xmlrpc.XPathValueGetInt(v_3, "page"); err != nil {
			return
		}

		v_4 := root.FindElement("param[3]/value")
		if v_4 == nil {
			err = xmlrpc.Errorf(400, "could not find isit")
			return
		}

		var isit bool
		if isit, err = xmlrpc.XPathValueGetBool(v_4, "isit"); err != nil {
			return
		}

		// If following method call fails there are 2 possible reasons:
		// 1. you have either changed method signature or you deleted method. Please re-run "go generate"
		// 2. you have probably found a bug and you should file issue on github.
		// @TODO: add panic recovery that returns error with 500 code

		var result_1 []string

		result_1, err = s.Search(query, page, isit)

		// create *etree.Document
		doc = etree.NewDocument()
		doc.CreateProcInst("xml", "version=\"1.0\" encoding=\"UTF-8\"")
		methodResponse_5 := doc.CreateElement("methodResponse")
		if err != nil {

			// move this code to error.
			fault_10 := methodResponse_5.CreateElement("fault")

			code_9 := 500

			// Try to cast error to xmlrpc.Error (with code added)
			if code_6, ok_8 := err.(xmlrpc.Error); ok_8 {
				code_9 = code_6.Code()
			}

			struct_7 := fault_10.CreateElement("value").CreateElement("struct")

			member_11 := struct_7.CreateElement("member")
			member_11.CreateElement("name").SetText("faultCode")
			member_11.CreateElement("value").CreateElement("int").SetText(strconv.Itoa(code_9))

			member_12 := struct_7.CreateElement("member")
			member_12.CreateElement("name").SetText("faultString")
			member_12.CreateElement("value").CreateElement("string").SetText(err.Error())

		} else {
			// here is place where we need to hydrate results
			v_13 := methodResponse_5.CreateElement("params").CreateElement("param").CreateElement("value")
			array_data_14 := v_13.CreateElement("array").CreateElement("data")
			for _, item_15 := range result_1 {
				value_16 := array_data_14.CreateElement("value")
				value_16.CreateElement("string").SetText(item_15)

			}

		}
	default:
		// method not found, this should not happened since we check whether method exists
		err = xmlrpc.ErrMethodNotFound
		return
	}
	return
}

go-xmlrpc has handler api so you can register your service instance (pointer) to handler and directly pass as http.Handler

handler := xmlrpc.Handler()

// We pass Config as example so you see that you can provide database connection or any other resource to service. 
if err := handler.AddService(&HelloService{Config:Config}, "hello"); err != nil {
    panic(err)
}

You can then call methods hello.Search with your favorite xmlrpc client. You can use then handler directly in your favorite mux router since it is Handler.

Return values:

Your service methods must return either:

  • error - simple error or xmlrpc.Error with code (xmlrpc.Errorf(400, "this %s", "error))
  • result and error

This is because xml rpc should return at least error.

Error:

If you return xmlrpc error with added code it will be addedded to result.fault. Otherwise error code will be 500.

Features:

  • since go-xmlrpc generates code in your package, you can use also unexported methods (yay)
  • you can register your services with instantiated database connections, or other variables
  • Automatically adds system.listMethods with all available methods
  • inspect service method arguments and return values recursively (yay nice!)

Limitations:

  • Registered services must be pointers (just to be sure all your methods are usable)
  • arguments currently don't support pointers (will be used in the future for non required arguments)

Gotchas:

Don't forget to rerun go generate when you either:

  • change definition of service methods
  • remove service methods
  • add service methods

TODO:

  • Add support for missing types (unsigned integer family)
  • Add proper error messages to parse errors (with whole path).
  • Cleanup code generation with proper documentation
  • Possibly remove temporary variables in parsing code.

Contributions:

Your PRs are welcome

Author:

phonkee

Documentation

Overview

Generator generates two structures, one for parameters one for result values.

Result values must be two, first is actual return value and second is error. If error is returned fault response will be generated.

Protocol handles first level of marshalling/unmarshalling

Xpath function helpers

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotService               = errors.New("argument is not service")
	ErrServiceAlreadyRegistered = errors.New("service already registered")
	ErrServiceMustBePointer     = errors.New("registered service must be pointer")
)
View Source
var (
	ErrMethodNotFound = errors.New("Method not found")
)

Functions

func Exit

func Exit(err interface{}, args ...interface{})

Exit prints error to stdout and exits with error

func GenerateVariableName

func GenerateVariableName(prefix ...string) string

GenerateVariableName generates unique variable name

func IsBlank

func IsBlank(value string) bool

IsBlank check trimmed value equal to ""

func IsNotBlank

func IsNotBlank(value string) bool

IsNotBlank is opposite of IsBlank :-D

func MD5

func MD5(value string) string

MD5 helper

func RenderTemplate

func RenderTemplate(tpl string, data map[string]interface{}, funcmaps ...template.FuncMap) string

RenderTemplate renders text template with data

func RenderTemplateInto

func RenderTemplateInto(w io.Writer, tpl string, data map[string]interface{}, funcmaps ...template.FuncMap)

func XMLWriteError

func XMLWriteError(element *etree.Element, err error)

XMLWriteError writes xml error

func XMLWriteStringSlice

func XMLWriteStringSlice(element *etree.Element, stringSlice []string)

XMLWriteStringSlice writes array of string slice

func XPathValueGetBool

func XPathValueGetBool(element *etree.Element, name string) (result bool, err error)

XPathValueGetBool Returns bool from value

func XPathValueGetBytes

func XPathValueGetBytes(element *etree.Element, name string) (result []byte, err error)

XPathValueGetBytes Returns []byte from value

func XPathValueGetFloat32

func XPathValueGetFloat32(element *etree.Element, name string) (result float32, err error)

XPathValueGetFloat32 Returns float64 from value

func XPathValueGetFloat64

func XPathValueGetFloat64(element *etree.Element, name string) (result float64, err error)

XPathValueGetFloat64 Returns float64 from value

func XPathValueGetInt

func XPathValueGetInt(element *etree.Element, name string) (result int, err error)

XPathValueGetInt Returns int from value

func XPathValueGetInt32

func XPathValueGetInt32(element *etree.Element, name string) (result int32, err error)

XPathValueGetInt64 Returns int64 from value

func XPathValueGetInt64

func XPathValueGetInt64(element *etree.Element, name string) (result int64, err error)

XPathValueGetInt64 Returns int64 from value

func XPathValueGetString

func XPathValueGetString(element *etree.Element, name string) (result string, err error)

XPathValueGetString Returns bool from value

Types

type Error

type Error interface {
	Code() int
	Error() string
}

func Errorf

func Errorf(code int, msg string, args ...interface{}) Error

Errorf creates new xmlrpc error with given code

type Generator

type Generator interface {
	// add service by its name
	AddService(name string) error

	// format returns formatted source code
	Format() []byte
}

Generator interface

func NewGenerator

func NewGenerator(filename string) (Generator, error)

NewGenerator returns Generator implementation

type Handler

type Handler interface {

	// AddService under given namespace
	AddService(service interface{}, name string) error

	// ListMethods returns all available xmlrpc methods
	ListMethods() []string

	// ServeHTTP satisfy http.Handler
	ServeHTTP(w http.ResponseWriter, r *http.Request)
}

Handler interface

func NewHandler

func NewHandler() Handler

NewHandler returns xmlrpc handler

type Param

type Param interface {
	// Name returns code name
	Name() string

	// Type returns type
	Type() string

	// SetType sets type (useful in case of named types)
	SetType(string)

	// Writes Field
	FromEtree(element string, resultvar string, errvar string) string

	// Writes param to element
	ToEtree(element string, resultvar string, errvar string) string

	// returns all imports for given param
	Imports() []string
}

New implementation of parameter

type Service

type Service interface {

	// Dispatch method dispatches xmlrpc call
	Dispatch(method string, root *etree.Element) (result *etree.Document, err error)

	// returns list of all rpc methods
	ListMethods() []string

	// check if service has method
	MethodExists(string) bool
}

Service interface must be satisfied when registering service This interface is satisfied when go generate is called

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL