Go Tutorial


Introduction

All Apache Thrift tutorials require that you have:

  1. The Apache Thrift Compiler and Libraries, see Download and Building from Source for more details.
  2. Generated the tutorial.thrift and shared.thrift files:

    thrift -r --gen go tutorial.thrift
    
  3. Followed all prerequisites listed below.

Prerequisites

Client

import (
    "context"
    "crypto/tls"
    "fmt"
    "tutorial"

    "github.com/apache/thrift/lib/go/thrift"
)

var defaultCtx = context.Background()

func handleClient(client *tutorial.CalculatorClient) (err error) {
    client.Ping(defaultCtx)
    fmt.Println("ping()")

    sum, _ := client.Add(defaultCtx, 1, 1)
    fmt.Print("1+1=", sum, "\n")

    work := tutorial.NewWork()
    work.Op = tutorial.Operation_DIVIDE
    work.Num1 = 1
    work.Num2 = 0
    quotient, err := client.Calculate(defaultCtx, 1, work)
    if err != nil {
        switch v := err.(type) {
        case *tutorial.InvalidOperation:
            fmt.Println("Invalid operation:", v)
        default:
            fmt.Println("Error during operation:", err)
        }
    } else {
        fmt.Println("Whoa we can divide by 0 with new value:", quotient)
    }

    work.Op = tutorial.Operation_SUBTRACT
    work.Num1 = 15
    work.Num2 = 10
    diff, err := client.Calculate(defaultCtx, 1, work)
    if err != nil {
        switch v := err.(type) {
        case *tutorial.InvalidOperation:
            fmt.Println("Invalid operation:", v)
        default:
            fmt.Println("Error during operation:", err)
        }
        return err
    } else {
        fmt.Print("15-10=", diff, "\n")
    }

    log, err := client.GetStruct(defaultCtx, 1)
    if err != nil {
        fmt.Println("Unable to get struct:", err)
        return err
    } else {
        fmt.Println("Check log:", log.Value)
    }
    return err
}

func runClient(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool) error {
    var transport thrift.TTransport
    var err error
    if secure {
        cfg := new(tls.Config)
        cfg.InsecureSkipVerify = true
        transport, err = thrift.NewTSSLSocket(addr, cfg)
    } else {
        transport, err = thrift.NewTSocket(addr)
    }
    if err != nil {
        fmt.Println("Error opening socket:", err)
        return err
    }
    transport, err = transportFactory.GetTransport(transport)
    if err != nil {
        return err
    }

Server

import (
    "crypto/tls"
    "fmt"
    "github.com/apache/thrift/lib/go/thrift"
    "tutorial"
)

func runServer(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool) error {
    var transport thrift.TServerTransport
    var err error
    if secure {
        cfg := new(tls.Config)
        if cert, err := tls.LoadX509KeyPair("server.crt", "server.key"); err == nil {
            cfg.Certificates = append(cfg.Certificates, cert)
        } else {
            return err
        }
        transport, err = thrift.NewTSSLServerSocket(addr, cfg)
    } else {
        transport, err = thrift.NewTServerSocket(addr)
    }

    if err != nil {
        return err
    }
    fmt.Printf("%T\n", transport)
    handler := NewCalculatorHandler()
    processor := tutorial.NewCalculatorProcessor(handler)
    server := thrift.NewTSimpleServer4(processor, transport, transportFactory, protocolFactory)

    fmt.Println("Starting the simple server... on ", addr)
    return server.Serve()
}

Server Handler

import (
    "context"
    "fmt"
    "shared"
    "strconv"
    "tutorial"
)

type CalculatorHandler struct {
    log map[int]*shared.SharedStruct
}

func NewCalculatorHandler() *CalculatorHandler {
    return &CalculatorHandler{log: make(map[int]*shared.SharedStruct)}
}

func (p *CalculatorHandler) Ping(ctx context.Context) (err error) {
    fmt.Print("ping()\n")
    return nil
}

func (p *CalculatorHandler) Add(ctx context.Context, num1 int32, num2 int32) (retval17 int32, err error) {
    fmt.Print("add(", num1, ",", num2, ")\n")
    return num1 + num2, nil
}

func (p *CalculatorHandler) Calculate(ctx context.Context, logid int32, w *tutorial.Work) (val int32, err error) {
    fmt.Print("calculate(", logid, ", {", w.Op, ",", w.Num1, ",", w.Num2, "})\n")
    switch w.Op {
    case tutorial.Operation_ADD:
        val = w.Num1 + w.Num2
        break
    case tutorial.Operation_SUBTRACT:
        val = w.Num1 - w.Num2
        break
    case tutorial.Operation_MULTIPLY:
        val = w.Num1 * w.Num2
        break
    case tutorial.Operation_DIVIDE:
        if w.Num2 == 0 {
            ouch := tutorial.NewInvalidOperation()
            ouch.WhatOp = int32(w.Op)
            ouch.Why = "Cannot divide by 0"
            err = ouch
            return
        }
        val = w.Num1 / w.Num2
        break
    default:
        ouch := tutorial.NewInvalidOperation()
        ouch.WhatOp = int32(w.Op)
        ouch.Why = "Unknown operation"
        err = ouch
        return
    }
    entry := shared.NewSharedStruct()
    entry.Key = logid
    entry.Value = strconv.Itoa(int(val))
    k := int(logid)
    /*
       oldvalue, exists := p.log[k]
       if exists {
         fmt.Print("Replacing ", oldvalue, " with ", entry, " for key ", k, "\n")
       } else {
         fmt.Print("Adding ", entry, " for key ", k, "\n")
       }
    */
    p.log[k] = entry
    return val, err
}

func (p *CalculatorHandler) GetStruct(ctx context.Context, key int32) (*shared.SharedStruct, error) {
    fmt.Print("getStruct(", key, ")\n")
    v, _ := p.log[int(key)]
    return v, nil
}

func (p *CalculatorHandler) Zip(ctx context.Context) (err error) {
    fmt.Print("zip()\n")
    return nil
}

Additional Information