| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package abeth |
| |
| import ( |
| "fmt" |
| "strconv" |
| "time" |
| |
| "github.com/rs/zerolog" |
| |
| "github.com/apache/plc4x/plc4go/spi/errors" |
| spiOptions "github.com/apache/plc4x/plc4go/spi/options" |
| ) |
| |
| // Configuration is what an ab-eth connection string can say about the connection. Ported from |
| // plc4j's AbEthConfiguration, which knows exactly these two options. |
| type Configuration struct { |
| // station is the DF1 destination address every request is addressed to. It ends up in the |
| // destinationAddress field of the DF1 request message. |
| station uint8 |
| // requestTimeout bounds the connect handshake and every single read. |
| requestTimeout time.Duration |
| } |
| |
| const ( |
| // defaultStation is plc4j's @IntDefaultValue(0) for the station option. |
| defaultStation = uint8(0) |
| // defaultRequestTimeout is plc4j's @IntDefaultValue(10_000) for the request-timeout-ms option. |
| defaultRequestTimeout = 10 * time.Second |
| ) |
| |
| // DefaultConfiguration is a connection without any options set. |
| func DefaultConfiguration() Configuration { |
| return Configuration{ |
| station: defaultStation, |
| requestTimeout: defaultRequestTimeout, |
| } |
| } |
| |
| // ParseFromOptions reads the connection options out of a parsed connection string. The timeout is |
| // spelled in milliseconds, the way plc4j's @IntDefaultValue(10_000) does. |
| func ParseFromOptions(localLog zerolog.Logger, connectionOptions map[string][]string) (Configuration, error) { |
| // Every option this driver reads goes through the reader, so the ones nothing read can be |
| // reported rather than silently discarded. Deferred, so no return path can skip it. |
| reader := spiOptions.NewOptionReader(localLog, connectionOptions) |
| defer reader.ReportUnknown("ab-eth") |
| |
| configuration := DefaultConfiguration() |
| |
| if stationString := reader.Get("station"); stationString != "" { |
| // The station is the DF1 destination address, which is a single byte on the wire. |
| parsedInt, err := strconv.ParseUint(stationString, 10, 8) |
| if err != nil { |
| return Configuration{}, errors.Wrapf(err, "Error parsing station %s (has to fit into a single byte)", stationString) |
| } |
| configuration.station = uint8(parsedInt) |
| } |
| |
| if requestTimeoutString := reader.Get("request-timeout-ms"); requestTimeoutString != "" { |
| parsedInt, err := strconv.ParseUint(requestTimeoutString, 10, 32) |
| if err != nil { |
| return Configuration{}, errors.Wrapf(err, "Error parsing request-timeout-ms %s", requestTimeoutString) |
| } |
| if parsedInt == 0 { |
| return Configuration{}, errors.New("request-timeout-ms must be greater than zero") |
| } |
| configuration.requestTimeout = time.Duration(parsedInt) * time.Millisecond |
| } |
| |
| return configuration, nil |
| } |
| |
| func (c Configuration) String() string { |
| return fmt.Sprintf("abeth.Configuration{station: %d, requestTimeout: %s}", c.station, c.requestTimeout) |
| } |