-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added initial DataSet implementation
- Loading branch information
1 parent
cd27ff7
commit c157eda
Showing
10 changed files
with
901 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
//****************************************************************************************************** | ||
// AdvancedSubscribe.go - Gbtc | ||
// | ||
// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. | ||
// | ||
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See | ||
// the NOTICE file distributed with this work for additional information regarding copyright ownership. | ||
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this | ||
// file except in compliance with the License. You may obtain a copy of the License at: | ||
// | ||
// http://opensource.org/licenses/MIT | ||
// | ||
// Unless agreed to in writing, the subject software distributed under the License is distributed on an | ||
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the | ||
// License for the specific language governing permissions and limitations. | ||
// | ||
// Code Modification History: | ||
// ---------------------------------------------------------------------------------------------------- | ||
// 09/23/2021 - J. Ritchie Carroll | ||
// Generated original version of source code. | ||
// | ||
//****************************************************************************************************** | ||
|
||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"math" | ||
"os" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/sttp/goapi/sttp" | ||
"github.com/sttp/goapi/sttp/transport" | ||
) | ||
|
||
// AdvancedSubscriber is a simple STTP data subscriber implementation. | ||
type AdvancedSubscriber struct { | ||
sttp.SubscriberBase // Provides default implementation | ||
} | ||
|
||
// NewAdvancedSubscriber creates a new AdvancedSubscriber. | ||
func NewAdvancedSubscriber() *AdvancedSubscriber { | ||
subscriber := &AdvancedSubscriber{} | ||
subscriber.SubscriberBase = sttp.NewSubscriberBase(subscriber) | ||
return subscriber | ||
} | ||
|
||
func main() { | ||
hostname, port := parseCmdLineArgs() | ||
subscriber := NewAdvancedSubscriber() | ||
subscription := subscriber.Subscription() | ||
|
||
subscriber.Hostname = hostname | ||
subscriber.Port = port | ||
|
||
subscription.FilterExpression = "FILTER TOP 20 ActiveMeasurements WHERE True" | ||
subscription.UdpDataChannel = true | ||
subscription.DataChannelLocalPort = 9600 | ||
subscription.UseMillisecondResolution = true | ||
|
||
subscriber.Connect() | ||
defer subscriber.Dispose() | ||
|
||
reader := bufio.NewReader(os.Stdin) | ||
reader.ReadRune() | ||
} | ||
|
||
// ReceivedMetadata handles reception of the metadata response. | ||
func (ss *AdvancedSubscriber) ReceivedMetadata(metadata []byte) { | ||
ss.StatusMessage(fmt.Sprintf("Received %d bytes of metadata", len(metadata))) | ||
} | ||
|
||
// SubscriptionUpdated handles notifications that a new SignalIndexCache has been received. | ||
func (ss *AdvancedSubscriber) SubscriptionUpdated(signalIndexCache *transport.SignalIndexCache) { | ||
ss.StatusMessage(fmt.Sprintf("Received signal index cache with %d mappings", signalIndexCache.Count())) | ||
} | ||
|
||
var lastMessageDisplay time.Time | ||
|
||
// ReceivedNewMeasurements handles reception of new measurements. | ||
func (ss *AdvancedSubscriber) ReceivedNewMeasurements(measurements []transport.Measurement) { | ||
|
||
if time.Since(lastMessageDisplay).Seconds() < 5.0 { | ||
return | ||
} | ||
|
||
defer func() { lastMessageDisplay = time.Now() }() | ||
|
||
if lastMessageDisplay.IsZero() { | ||
ss.StatusMessage("Receiving measurements...") | ||
return | ||
} | ||
|
||
var message strings.Builder | ||
|
||
message.WriteString(strconv.FormatUint(ss.TotalMeasurementsReceived(), 10)) | ||
message.WriteString(" measurements received so far...\n") | ||
message.WriteString("Timestamp: ") | ||
message.WriteString(measurements[0].DateTime().Format("2006-01-02 15:04:05.999999999")) | ||
message.WriteRune('\n') | ||
message.WriteString("\tID\tSignal ID\t\t\t\tValue\n") | ||
|
||
for i := 0; i < len(measurements); i++ { | ||
measurement := measurements[i] | ||
metadata := ss.Metadata(&measurement) | ||
|
||
message.WriteRune('\t') | ||
message.WriteString(strconv.FormatUint(metadata.ID, 10)) | ||
message.WriteRune('\t') | ||
message.WriteString(measurement.SignalID.String()) | ||
message.WriteRune('\t') | ||
message.WriteString(strconv.FormatFloat(measurement.Value, 'f', 6, 64)) | ||
message.WriteRune('\n') | ||
} | ||
|
||
ss.StatusMessage(message.String()) | ||
} | ||
|
||
// ConnectionTerminated handles notification that a connection has been terminated. | ||
func (ss *AdvancedSubscriber) ConnectionTerminated() { | ||
// Call base implementation which will display a connection terminated message to stderr | ||
ss.SubscriberBase.ConnectionTerminated() | ||
|
||
// Reset last message display time on disconnect | ||
lastMessageDisplay = time.Time{} | ||
} | ||
|
||
func parseCmdLineArgs() (string, uint16) { | ||
args := os.Args | ||
|
||
if len(args) < 3 { | ||
fmt.Println("Usage:") | ||
fmt.Println(" AdvancedSubscribe HOSTNAME PORT") | ||
os.Exit(1) | ||
} | ||
|
||
hostname := args[1] | ||
port, err := strconv.Atoi(args[2]) | ||
|
||
if err != nil { | ||
fmt.Printf("Invalid port number \"%s\": %s\n", args[1], err.Error()) | ||
os.Exit(2) | ||
} | ||
|
||
if port < 1 || port > math.MaxUint16 { | ||
fmt.Printf("Port number \"%s\" is out of range: must be 1 to %d\n", args[1], math.MaxUint16) | ||
os.Exit(2) | ||
} | ||
|
||
return hostname, uint16(port) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
//****************************************************************************************************** | ||
// DataColumn.go - Gbtc | ||
// | ||
// Copyright © 2021, Grid Protection Alliance. All Rights Reserved. | ||
// | ||
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See | ||
// the NOTICE file distributed with this work for additional information regarding copyright ownership. | ||
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this | ||
// file except in compliance with the License. You may obtain a copy of the License at: | ||
// | ||
// http://opensource.org/licenses/MIT | ||
// | ||
// Unless agreed to in writing, the subject software distributed under the License is distributed on an | ||
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the | ||
// License for the specific language governing permissions and limitations. | ||
// | ||
// Code Modification History: | ||
// ---------------------------------------------------------------------------------------------------- | ||
// 09/23/2021 - J. Ritchie Carroll | ||
// Generated original version of source code. | ||
// | ||
//****************************************************************************************************** | ||
|
||
package metadata | ||
|
||
// DataColumn represents a column, i.e., a field, in a DataTable defining a name and a data type. | ||
// Data columns can also be computed where its value would be derived from other columns and | ||
// functions (https://sttp.github.io/documentation/filter-expressions/) defined in an expression. | ||
type DataColumn struct { | ||
parent *DataTable | ||
name string | ||
dataType DataTypeEnum | ||
expression string | ||
computed bool | ||
index int | ||
} | ||
|
||
func newDataColumn(parent *DataTable, name string, dataType DataTypeEnum, expression string) *DataColumn { | ||
return &DataColumn{ | ||
parent: parent, | ||
name: name, | ||
dataType: dataType, | ||
expression: expression, | ||
computed: len(expression) > 0, | ||
index: -1, | ||
} | ||
} | ||
|
||
// Parent gets the parent DataTable of the DataColumn. | ||
func (dc *DataColumn) Parent() *DataTable { | ||
return dc.parent | ||
} | ||
|
||
// Name gets the column name of the DataColumn. | ||
func (dc *DataColumn) Name() string { | ||
return dc.name | ||
} | ||
|
||
// Type gets the column DataType enumeration value of the DataColumn. | ||
func (dc *DataColumn) Type() DataTypeEnum { | ||
return dc.dataType | ||
} | ||
|
||
// Expression gets the column expression value of the DataColumn, if any. | ||
func (dc *DataColumn) Expression() string { | ||
return dc.expression | ||
} | ||
|
||
// Computed gets a flag that determines if the DataColumn is a computed value, | ||
// i.e., has a defined expression. | ||
func (dc *DataColumn) Computed() bool { | ||
return dc.computed | ||
} | ||
|
||
// Index gets the index of the DataColumn within its parent DataTable columns collection. | ||
func (dc *DataColumn) Index() int { | ||
return dc.index | ||
} |
Oops, something went wrong.