github.com/Comcast/plax@v0.8.32/dsl/mother.go (about) 1 /* 2 * Copyright 2021 Comcast Cable Communications Management, LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * SPDX-License-Identifier: Apache-2.0 17 */ 18 19 package dsl 20 21 import ( 22 "encoding/json" 23 "fmt" 24 "time" 25 26 "github.com/Comcast/plax/subst" 27 ) 28 29 // MotherRequest is the structure for a request to Mother. 30 // 31 // Every MotherRequest will get exactly one MotherResponse. 32 type MotherRequest struct { 33 Make *MotherMakeRequest `json:"make"` 34 } 35 36 // MotherMakeRequest is the structure for a request to make a new 37 // channel. 38 type MotherMakeRequest struct { 39 // Name is the requested name for the channel to be created. 40 Name string `json:"name"` 41 42 // Type is something like 'mqtt', 'httpclient', or 'sqs' (the 43 // types that are registered with a (or The) ChannelRegistry). 44 Type ChanKind `json:"type"` 45 46 // Config is the configuration (if any) for the requested channel. 47 Config interface{} `json:"config,omitempty"` 48 } 49 50 // MotherResponse is the structure of the generic response to a 51 // request. 52 type MotherResponse struct { 53 // Request is the request the provoked this response. 54 Request *MotherRequest `json:"request"` 55 56 // Success reports whether the request succeeded. 57 Success bool `json:"success"` 58 59 // Error, if not zero, is an error message for a failed 60 // request. 61 Error string `json:"error,omitempty"` 62 } 63 64 // Mother is the mother of all (other) channels. 65 // 66 // Mother ('mother') can make channels, and Mother is itself a 67 // Channel. 68 type Mother struct { 69 t *Test 70 c chan Msg 71 } 72 73 func NewMother(ctx *Ctx, _ interface{}) (*Mother, error) { 74 return &Mother{ 75 c: make(chan Msg, 1024), 76 }, nil 77 } 78 79 func (c *Mother) DocSpec() *DocSpec { 80 return &DocSpec{ 81 Chan: &Mother{}, 82 Input: &MotherRequest{}, 83 Output: &MotherResponse{}, 84 } 85 } 86 87 func (c *Mother) Kind() ChanKind { 88 return "mother" 89 } 90 91 func (c *Mother) Open(ctx *Ctx) error { 92 return nil 93 } 94 95 func (c *Mother) Close(ctx *Ctx) error { 96 return nil 97 } 98 99 func (c *Mother) Sub(ctx *Ctx, topic string) error { 100 ctx.Logf("Mother.Sub %s", topic) 101 return nil 102 } 103 104 // Pub sends a request to Mother. 105 // 106 // The message payload should represent a MotherRequest in JSON. 107 func (c *Mother) Pub(ctx *Ctx, m Msg) error { 108 ctx.Logf("Mother.Pub %T %v", m.Payload, m.Payload) 109 110 var ( 111 req MotherRequest 112 resp MotherResponse 113 ) 114 115 punt := func(err error) error { 116 if err != nil { 117 resp.Success = false 118 resp.Error = err.Error() 119 } 120 js, err := subst.JSONMarshal(&resp) 121 if err != nil { 122 return err 123 } 124 return c.To(ctx, Msg{ 125 Payload: string(js), 126 }) 127 } 128 129 // Parse the payload as a MotherRequest. 130 if err := json.Unmarshal([]byte(m.Payload), &req); err != nil { 131 return punt(err) 132 } 133 134 resp.Request = &req 135 136 // Handle the request. 137 138 if req.Make == nil { 139 return punt(fmt.Errorf("Only 'make' supported")) 140 } 141 142 if _, have := c.t.Chans[req.Make.Name]; have { 143 return punt(fmt.Errorf("Already have chan '%s'", req.Make.Name)) 144 } 145 146 // Special cases 147 switch req.Make.Type { 148 case "cmd": 149 if m, is := req.Make.Config.(map[string]interface{}); is { 150 m["name"] = req.Make.Name 151 } 152 } 153 154 ch, err := c.t.makeChan(ctx, req.Make.Type, req.Make.Config) 155 if err != nil { 156 return punt(err) 157 } 158 159 if err := ch.Open(ctx); err != nil { 160 return punt(err) 161 } 162 163 resp.Success = true 164 c.t.Chans[req.Make.Name] = ch 165 166 return punt(nil) 167 } 168 169 func (c *Mother) Recv(ctx *Ctx) chan Msg { 170 ctx.Logf("Mother.Recv") 171 return c.c 172 } 173 174 func (c *Mother) Kill(ctx *Ctx) error { 175 return fmt.Errorf("Kill is not supported by a %T", c) 176 } 177 178 func (c *Mother) To(ctx *Ctx, m Msg) error { 179 ctx.Logf("Mother To %s", m.Payload) 180 m.ReceivedAt = time.Now().UTC() 181 select { 182 case <-ctx.Done(): 183 case c.c <- m: 184 default: 185 panic("Warning: Mother channel full") 186 } 187 return nil 188 }