2022-02-06 07:06:32 +00:00

112 lines
2.9 KiB
Go

// Copyright (C) 2017 Michael J. Fromberger. All Rights Reserved.
// Program server demonstrates how to set up a JSON-RPC 2.0 server using the
// github.com/creachadair/jrpc2 package.
//
// Usage (see also the client example):
//
// go build github.com/creachadair/jrpc2/tools/examples/server
// ./server -address :8080
//
// See also examples/client/client.go.
package main
import (
"context"
"flag"
"log"
"net"
"github.com/creachadair/jrpc2"
"github.com/creachadair/jrpc2/channel"
"github.com/creachadair/jrpc2/code"
"github.com/creachadair/jrpc2/handler"
"github.com/creachadair/jrpc2/metrics"
"github.com/creachadair/jrpc2/server"
)
// A binop carries a pair of integers for use as parameters.
type binop struct {
X, Y int
}
// Add returns the sum of vs, or 0 if len(vs) == 0.
func Add(ctx context.Context, vs []int) int {
sum := 0
for _, v := range vs {
sum += v
}
return sum
}
// Sub returns the difference x - y.
func Sub(ctx context.Context, x, y int) int { return x - y }
// Mul returns the product arg.X * arg.Y.
func Mul(ctx context.Context, x, y int) int { return x * y }
// Div converts its arguments to floating point and returns their ratio.
func Div(ctx context.Context, arg binop) (float64, error) {
if arg.Y == 0 {
return 0, jrpc2.Errorf(code.InvalidParams, "zero divisor")
}
return float64(arg.X) / float64(arg.Y), nil
}
// Status simulates a health check, reporting "OK" to all callers. It also
// demonstrates the use of server-side push.
func Status(ctx context.Context) (string, error) {
if err := jrpc2.ServerFromContext(ctx).Notify(ctx, "pushback", []string{"hello, friend"}); err != nil {
return "BAD", err
}
return "OK", nil
}
// Alert implements a notification handler that logs its argument.
func Alert(ctx context.Context, a map[string]string) error {
log.Printf("[ALERT]: %s", a["message"])
return nil
}
var (
address = flag.String("address", "", "Service address")
maxTasks = flag.Int("max", 1, "Maximum concurrent tasks")
)
func main() {
flag.Parse()
if *address == "" {
log.Fatal("You must provide a network -address to listen on")
}
// Bind the services to their given names.
mux := handler.ServiceMap{
"Math": handler.Map{
"Add": handler.New(Add),
"Sub": handler.NewPos(Sub, "X", "Y"),
"Mul": handler.NewPos(Mul, "X", "Y"),
"Div": handler.New(Div),
"Status": handler.New(Status),
},
"Post": handler.Map{
"Alert": handler.New(Alert),
},
}
lst, err := net.Listen(jrpc2.Network(*address))
if err != nil {
log.Fatalln("Listen:", err)
}
log.Printf("Listening at %v...", lst.Addr())
acc := server.NetAccepter(lst, channel.Line)
ctx := context.Background()
server.Loop(ctx, acc, server.Static(mux), &server.LoopOptions{
ServerOptions: &jrpc2.ServerOptions{
Logger: jrpc2.StdLogger(nil),
Concurrency: *maxTasks,
Metrics: metrics.New(),
AllowPush: true,
},
})
}