Пример #1
0
// Get package common
func (g GenRoot) PackageOut() (res []byte, err error) {
	res, err = tpl.Run("package", TPL_PACKAGE, g)
	if err != nil {
		return
	}
	return
}
Пример #2
0
// Generate processor type.
func (p *GenProcessor) Processor() (res []byte, err error) {
	src := `package {{ .Options.Package }}

	import (
		"{{ .Options.Core }}"
		. "{{ .Options.Core }}/builtin"
		"golang.org/x/net/context"
		"bytes"
		"fmt"
		"time"
	)

	const (
		processor_VERSION = TL_VERSION
	)

	type ProcessorFactory struct {
		handler Handler
		encoderFactory tl.EncoderFactory
		decoderFactory tl.DecoderFactory
		waitress tl.Waitress
		idBrokerFactory tl.IDBrokerFactory
	}

	func NewProcessorFactory(handler Handler, encoderFactory tl.EncoderFactory, decoderFactory tl.DecoderFactory, waitress tl.Waitress, idBrokerFactory tl.IDBrokerFactory) tl.ProcessorFactory {
		return &ProcessorFactory{handler, encoderFactory, decoderFactory, waitress, idBrokerFactory}
	}

	func (f *ProcessorFactory) GetProcessor(ctx context.Context, id int64) tl.Processor {
		return NewProcessor(ctx, f.handler, f.encoderFactory, f.decoderFactory, f.waitress, f.idBrokerFactory.GetIDBroker(id))
	}

	type Processor struct {
		ctx context.Context
		handler Handler
		tl.EncoderFactory
		tl.DecoderFactory
		tl.Waitress
		tl.IDBroker
	}

	func NewProcessor(
		ctx context.Context,
		handler Handler,
		encoderFactory tl.EncoderFactory,
		decoderFactory tl.DecoderFactory,
		waitress tl.Waitress,
		idBroker tl.IDBroker,
	) *Processor {
		return &Processor{
			ctx,
			handler,
			encoderFactory,
			decoderFactory,
			waitress,
			idBroker,
		}
	}

	func (p *Processor) Process(reqCtx tl.RequestContext, data []byte, result tl.ProcessorResult) (err error) {
		decoder := p.DecoderFactory.GetDecoder(bytes.NewBuffer(data))
		box := &ObjectBox{}
		if err = box.Read(decoder, p.Waitress, reqCtx.Session); err != nil {
			return err
		}
		bare, err := box.Bare()
		if err != nil {
			return err
		}

		// Add ack if needed
		if (reqCtx.SeqNo & 1) == 1 {
			if err = p.sendAck(result, reqCtx); err != nil {
				return err
			}
		}

		switch bare.(type) {
		case *MsgsAck:
			for _, msgId := range bare.(*MsgsAck).MsgIds {
				p.Waitress.DoneAck(reqCtx.Session, msgId)
			}
		case *MsgContainer:
			// Requeue messages
			for _, msg := range bare.(*MsgContainer).Messages {
				box := msg.Body
				buff := new(bytes.Buffer)
				encoder := p.EncoderFactory.GetEncoder(buff)
				if err = box.Write(encoder); err != nil {
					return err
				}
				newReqCtx := tl.RequestContext{
					reqCtx.Conn,
					reqCtx.Session,
					msg.MsgId,
					msg.Seqno,
				}
				if err = result.EnqueueRequest(newReqCtx, buff.Bytes()); err != nil {
					return err
				}
			}

		case *RpcResult:
			rpcResult := bare.(*RpcResult)
			var handlerErr error
			ctx := tl.HandlerContext{reqCtx, p, p.ctx}
			switch rpcResult.Result.(type) {
			{{range .RPCs}}
				{{if .WithResult}}
					{{range .GBox.Bares}}
						case *{{.Ident.ToName}}Res:
							handlerErr = p.handler.{{.Ident.ToName}}Result(ctx, rpcResult.ReqMsgId, rpcResult.Result.(*{{.Ident.ToName}}Res).Arg, rpcResult.RpcError)
					{{end}}
				{{end}}
			{{end}}
			default:
				// unknown constructor
				handlerErr = fmt.Errorf("unknown RpcResult for %0xd (ctx %v)", rpcResult.ReqMsgId, reqCtx)
			}
			err = p.Waitress.DoneResult(reqCtx.Session, rpcResult.ReqMsgId, handlerErr)

		{{ range .RPCs }}
			{{ if eq .WithResult false }}
			case *{{.GBox.Ident.ToName}}:
				// Unwrapped {{.GBox.Ident.ToName}} result
				ctx := tl.HandlerContext{reqCtx, p, p.ctx}
				handlerErr := p.handler.{{.GBox.Ident.ToName}}(ctx, bare.(*{{.GBox.Ident.ToName}}).Boxed())
				err = p.Waitress.DoneResult(reqCtx.Session, reqCtx.MessageID, handlerErr)
			{{end}}
		{{end}}

		{{ range .RPCs }}
			{{$RPC:=.}}
			{{range .GBox.Bares}}
				{{$ARG_SRC := printf "bare.(*%s)" .Ident.ToName}}
				{{ if $RPC.WithResult }}
				case *{{.Ident.ToName}}:
					// {{.Ident.ToName}} request with wrapped result
					ctx := tl.HandlerContext{reqCtx, p, p.ctx}
					res, handlerErr := p.handler.{{.Ident.ToName}}({{$RPC.HandlerArgs . $ARG_SRC "ctx" ""}})
					var resMsgID int64
					resMsgID, err = p.IDBroker.NewMessageID(reqCtx.Session, time.Now(), 1)
					if err != nil {
						return
					}
					err = p.sendResponse(
						result,
						tl.ResponseContext{reqCtx, resMsgID, reqCtx.SeqNo + 2},
						(&RpcResult{reqCtx.MessageID, &{{.Ident.ToName}}Res{res}, handlerErr}).Box())
				{{end}}
			{{end}}
		{{end}}

		{{ range .RPCs }}
			{{$RPC:=.}}
			{{range .GBox.Bares}}
				{{$ARG_SRC := printf "bare.(*%s)" .Ident.ToName}}
				{{ if eq $RPC.WithResult false }}
				case *{{.Ident.ToName}}:
					// {{.Ident.ToName}} request with unwrapped {{.BoxIdent}} result
					ctx := tl.HandlerContext{reqCtx, p, p.ctx}
					var res {{.BoxIdent}}
					var resCtx tl.ResponseContext
					res, resCtx, err = p.handler.{{.Ident.ToName}}({{$RPC.HandlerArgs . $ARG_SRC "ctx" ""}})
					if err != nil {
						return
					}
					err = p.sendResponse(result, resCtx, &res)
				{{end}}
			{{end}}
		{{end}}
		}

		return
	}

	// Send ack
	func (p *Processor) sendAck(result tl.ProcessorResult, reqCtx tl.RequestContext) (err error) {
		resMsgID, err := p.IDBroker.NewMessageID(reqCtx.Session, time.Now(), 1)
		if err != nil {
			return
		}
		err = p.sendResponse(
			result,
			tl.ResponseContext{reqCtx, resMsgID, reqCtx.SeqNo + 1},
			(&MsgsAck{[]int64{reqCtx.MessageID}}).Box())
		return
	}

	// Send response and register ack in waitress
	func (p *Processor) sendResponse(result tl.ProcessorResult, resCtx tl.ResponseContext, box tl.Box) (err error) {
		buff := new(bytes.Buffer)
		encoder := p.EncoderFactory.GetEncoder(buff)
		if err = box.Write(encoder); err != nil {
			return err
		}
		if (resCtx.SeqNo & 1) == 1 {
			if err = p.Waitress.WaitAck(resCtx.Request.Session, resCtx.MessageID); err != nil {
				return err
			}
		}
		err = result.SendResponse(resCtx, buff.Bytes())
		return
	}
	`
	res, err = tpl.Run("pipe", src, p)
	return
}
Пример #3
0
// Get generated source
func (b GenBox) Res() (res []byte, err error) {
	res, err = tpl.Run(b.Filename(), TPL_BOX, b)
	return
}