Work on collection of protocols and requirements
Go / lint (push) Failing after 16s Details
Go / build (push) Failing after 2m6s Details

This commit is contained in:
Marcel M. Otte 2023-09-17 12:49:41 +02:00
parent 608122e5a1
commit 09d4b338d2
25 changed files with 718 additions and 540 deletions

164
cop/collection.go Normal file
View File

@ -0,0 +1,164 @@
package cop
import (
"errors"
"fmt"
"io/fs"
"log"
"os"
"os/user"
"path"
"path/filepath"
"strings"
"github.com/go-git/go-git/v5"
"gitea.mmo.to/ppForge/ppforge/protocol"
)
// ProtocolCollectionList is a list of all databases, with the most simple interface
type ProtocolCollectionList struct {
PCs []COP
}
// ProtocolCollectionEntry is a single entry in the file database, additionally to the meta data the path is required
type ProtocolCollectionEntry struct {
Path string
Protocol protocol.ProtocolMeta
}
// Init initializes the databases, opens the default one and checks for others if available
func Init() *ProtocolCollectionList {
// initialize main list
databases := ProtocolCollectionList{[]COP{}}
// initialize default db
user, err := user.Current()
if err != nil {
log.Printf("Current user not obtainable: %s", err)
log.Fatal("Impossible to open default database")
}
pathlist := []string{user.HomeDir, ".config", "ppforge"}
fdb := FileCOP{COP{map[string]ProtocolCollectionEntry{}, false}, path.Join(pathlist...)}
fdb.Open(path.Join(pathlist...))
fdb.UpdateCollection()
databases.PCs = append(databases.PCs, fdb.COP)
log.Printf("Amount of databases available %d", len(databases.PCs))
return &databases
}
// Get a full protocol from a database entry
func (de *ProtocolCollectionEntry) Get() (*protocol.Protocol, error) {
return protocol.LoadNew(de.Path)
}
// COP represents a Collection of Protocols
type COP struct {
protocols map[string]ProtocolCollectionEntry
closed bool
}
// FileCOP implements
type FileCOP struct {
COP
Path string
}
// FileCOPFromGitRemote implements retrieving the latest stuff from an external git remote additionally to the FileDatabase functionality
type FileCOPFromGitRemote struct {
FileCOP
RemoteGitRepository string
gitRepo git.Repository
}
// Open the database
func (fd *FileCOP) Open(path string) error {
fileinfo, err := os.Stat(path)
if err == os.ErrNotExist {
return err
}
if !fileinfo.IsDir() {
return fmt.Errorf("Path %s is not a directory", path)
}
fd.Path = path
fd.closed = false
return nil
}
// Close the database and free the data
func (fd *FileCOP) Close() error {
fd.closed = true
return nil
}
// Protocols returns the map of protocols or an error if the first read failed
func (fd *FileCOP) Protocols() ([]ProtocolCollectionEntry, error) {
if fd.closed {
return nil, errors.New("COP closed, no protocols to deliver")
}
entries := []ProtocolCollectionEntry{}
if !fd.closed && len(fd.protocols) == 0 {
fd.protocols = map[string]ProtocolCollectionEntry{}
err := fd.UpdateCollection()
if err != nil {
return nil, err
}
}
if entries == nil || len(entries) == 0 {
entries = make([]ProtocolCollectionEntry, 0)
for _, v := range fd.protocols {
entries = append(entries, v)
}
}
return entries, nil
}
// Add puts a new protocol into the path of the file database
func (fd *FileCOP) Add(prot *protocol.Protocol) error {
if fd.closed {
return errors.New("Cannot add, FileCOP is closed")
}
p := path.Join(fd.Path, prot.Metadata.Name, ".protocoljson")
err := prot.Save(p)
if err == nil {
fd.protocols[prot.Metadata.Name] = ProtocolCollectionEntry{p, prot.Metadata}
}
return err
}
// Update updates an existing entry through saving the contents of the protocol to the file, or just adding it anew
func (fd *FileCOP) Update(prot *protocol.Protocol) error {
if fd.closed {
return errors.New("Cannot update, FileCOP is closed")
}
if v, ok := fd.protocols[prot.Metadata.Name]; ok {
v.Protocol = prot.Metadata
return prot.Save(v.Path)
}
return fd.Add(prot)
}
// UpdateCollection just rereads all files
func (fd *FileCOP) UpdateCollection() error {
if fd.closed {
return errors.New("Cannot update, FileCOP is closed")
}
// recurse recursively through the path
if fd.protocols == nil {
fd.protocols = make(map[string]ProtocolCollectionEntry)
}
err := filepath.Walk(fd.Path, func(path string, info fs.FileInfo, err error) error {
if !info.IsDir() && strings.HasSuffix(info.Name(), ".protocoljson") {
prot, err := protocol.LoadNew(path)
if err == nil {
// add to map
// add to map
entry := ProtocolCollectionEntry{path, prot.Metadata}
fd.protocols[prot.Metadata.Name] = entry
}
return err
}
return nil
})
return err
}

59
cop/collection_test.go Normal file
View File

@ -0,0 +1,59 @@
package cop
import (
"fmt"
"os"
"path"
"testing"
)
func TestOpen(t *testing.T) {
fcop := FileCOP{}
wd, err := os.Getwd()
if err != nil {
fmt.Printf("Os error: %s", err)
t.Fail()
}
fcop.Open(path.Join(wd, "..", "test", "cop"))
l, err := fcop.Protocols()
if err != nil {
t.Fail()
}
for k, v := range fcop.protocols {
fmt.Printf("%s->%s\n", k, v.Path)
}
for _, pce := range l {
fmt.Printf("%s//%s\n", pce.Path, pce.Protocol.Name)
}
}
func TestClosed(t *testing.T) {
fcop := FileCOP{}
wd, err := os.Getwd()
if err != nil {
fmt.Printf("Os error: %s", err)
t.Fail()
}
fcop.Open(path.Join(wd, "..", "test", "cop"))
fcop.Close()
l, err := fcop.Protocols()
if err == nil || l != nil {
fmt.Println("Protocols did not deliver error")
t.Fail()
}
err = fcop.Add(nil)
if err == nil {
fmt.Println("Add did not deliver error")
t.Fail()
}
err = fcop.Update(nil)
if err == nil {
fmt.Println("Update did not deliver error")
t.Fail()
}
err = fcop.UpdateCollection()
if err == nil {
fmt.Println("UpdateCollection did not deliver error")
t.Fail()
}
}

View File

@ -1,179 +0,0 @@
package dop
import (
"fmt"
"io/fs"
"log"
"os"
"os/user"
"path"
"path/filepath"
"github.com/go-git/go-git/v5"
"gitea.mmo.to/ppForge/ppforge/protocol"
"gitea.mmo.to/ppForge/ppforge/protocolctl"
)
// ProtocolDictionaryList is a list of all databases, with the most simple interface
type ProtocolDictionaryList struct {
PDs []ProtocolDictionaryProvider
}
// ProtocolDictionaryProvider is a simple protocol database interface, which only provides open/close and retrieving the contents
type ProtocolDictionaryProvider interface {
// Open opens a new database
Open(path string) error
// Close closes a database (only internal flag set)
Close() error
// Protocols returns the content of the database as map, an error if the first read of the database failed
Protocols() ([]ProtocolDictionaryEntry, error)
}
// ProtocolDatabaseManager is a complex protocol database interface, which allows adding, updating and refreshing of the content
type ProtocolDatabaseManager interface {
Add(prot *protocol.ProtocolStructure) error
Update(prot *protocol.ProtocolStructure) error
// no remove.
UpdateDatabase() error // scans for new protocols
}
// ProtocolDictionaryEntry is a single entry in the file database, additionally to the meta data the path is required
type ProtocolDictionaryEntry struct {
Path string
Protocol protocol.DOPMeta
}
// Init initializes the databases, opens the default one and checks for others if available
func Init() *ProtocolDictionaryList {
// initialize main list
databases := ProtocolDictionaryList{[]ProtocolDictionaryProvider{}}
// initialize default db
user, err := user.Current()
if err != nil {
log.Printf("Current user not obtainable: %s", err)
log.Fatal("Impossible to open default database")
}
pathlist := []string{user.HomeDir, ".config", "ppforge"}
fdb := FileDOP{path.Join(pathlist...), map[string]ProtocolDictionaryEntry{}, false}
fdb.Open(path.Join(pathlist...))
fdb.UpdateDatabase()
databases.PDs = append(databases.PDs, fdb)
log.Printf("Amount of databases available %d", len(databases.PDs))
return &databases
}
// Get Retrieves the full set of databases
func (ppfdb *ProtocolDictionaryList) Get() []ProtocolDictionaryProvider {
return ppfdb.PDs
}
// Get a full protocol from a database entry
func (de *ProtocolDictionaryEntry) Get() (*protocol.ProtocolStructure, error) {
return protocolctl.LoadNew(de.Path)
}
// FileDOP implements ProtocolDatabaseProvider and ProtocolDatabaseManager
type FileDOP struct {
Path string
protocols map[string]ProtocolDictionaryEntry
closed bool
}
// FileDOPFromGitRemote implements retrieving the latest stuff from an external git remote additionally to the FileDatabase functionality
// TODO
type FileDOPFromGitRemote struct {
FileDOP
RemoteGitRepository string
gitRepo git.Repository
}
// Open the database
func (fd FileDOP) Open(path string) error {
fileinfo, err := os.Stat(path)
if err == os.ErrNotExist {
return err
}
if !fileinfo.IsDir() {
return fmt.Errorf("Path %s is not a directory", path)
}
fd.Path = path
fd.closed = false
return nil
}
// Close the database and free the data
func (fd FileDOP) Close() error {
for k := range fd.protocols {
delete(fd.protocols, k)
}
fd.closed = true
return nil
}
// Protocols returns the map of protocols or an error if the first read failed
func (fd FileDOP) Protocols() ([]ProtocolDictionaryEntry, error) {
entries := []ProtocolDictionaryEntry{}
if !fd.closed && len(fd.protocols) == 0 {
fd.protocols = map[string]ProtocolDictionaryEntry{}
// recurse recursively through the path
err := filepath.Walk(fd.Path, func(path string, info fs.FileInfo, err error) error {
if !info.IsDir() {
prot, err := protocolctl.LoadNew(path)
if err == nil {
// add to map
entry := ProtocolDictionaryEntry{path, prot.Metadata}
fd.protocols[prot.Metadata.Name] = entry
entries = append(entries, entry)
}
}
return nil
})
if err != nil {
return nil, err
}
}
if entries == nil || len(entries) == 0 {
entries = make([]ProtocolDictionaryEntry, len(fd.protocols))
for _, v := range fd.protocols {
entries = append(entries, v)
}
}
return entries, nil
}
// Add puts a new protocol into the path of the file database
func (fd *FileDOP) Add(prot *protocol.ProtocolStructure) error {
p := path.Join(fd.Path, prot.Metadata.Name, ".protocoljson")
err := protocolctl.Save(prot, p)
if err == nil {
fd.protocols[prot.Metadata.Name] = ProtocolDictionaryEntry{p, prot.Metadata}
}
return err
}
// Update updates an existing entry through saving the contents of the protocol to the file, or just adding it anew
func (fd *FileDOP) Update(prot *protocol.ProtocolStructure) error {
if v, ok := fd.protocols[prot.Metadata.Name]; ok {
v.Protocol = prot.Metadata
return protocolctl.Save(prot, v.Path)
}
return fd.Add(prot)
}
// UpdateDatabase just rereads all files
func (fd *FileDOP) UpdateDatabase() error {
// recurse recursively through the path
err := filepath.Walk(fd.Path, func(path string, info fs.FileInfo, err error) error {
if !info.IsDir() {
prot, err := protocolctl.LoadNew(path)
if err == nil {
// add to map
fd.protocols[prot.Metadata.Name] = ProtocolDictionaryEntry{path, prot.Metadata}
}
}
return nil
})
return err
}

View File

@ -1,9 +0,0 @@
package dop
import (
"testing"
)
func Test(t *testing.T) {
}

View File

@ -88,7 +88,7 @@ func NewMetadataProtocol() *ProtocolMetadata {
return &md return &md
} }
func (md *ProtocolMetadata) SetProtocol(prot *protocol.ProtocolStructure) { func (md *ProtocolMetadata) SetProtocol(prot *protocol.Protocol) {
setfunc := func(s string) { setfunc := func(s string) {
protocolctl.UpdateMetaData( protocolctl.UpdateMetaData(
prot, prot,
@ -105,7 +105,6 @@ func (md *ProtocolMetadata) SetProtocol(prot *protocol.ProtocolStructure) {
md.VersionValue.SetText(prot.Metadata.Version) md.VersionValue.SetText(prot.Metadata.Version)
md.DescValue.SetText(prot.Metadata.Description) md.DescValue.SetText(prot.Metadata.Description)
md.ExtendsValue.SetText(prot.Metadata.ExtensionTo) md.ExtendsValue.SetText(prot.Metadata.ExtensionTo)
md.OsiLayer.SetSelectedIndex(int(prot.Metadata.OSILayer))
md.TcpIpLayer.SetSelectedIndex(int(prot.Metadata.TCPIPLayer)) md.TcpIpLayer.SetSelectedIndex(int(prot.Metadata.TCPIPLayer))
md.SetChanged(setfunc) md.SetChanged(setfunc)
md.Representation.Refresh() md.Representation.Refresh()
@ -115,7 +114,7 @@ func (md *ProtocolMetadata) Unset() {
md.SetChanged(func(s string) {}) md.SetChanged(func(s string) {})
} }
func (md *PacketMetadata) SetData(pack *packet.Structure) { func (md *PacketMetadata) SetData(pack *packet.Packet) {
} }

View File

@ -17,10 +17,10 @@ type PacketEditor struct {
ShowShortHints bool ShowShortHints bool
Reference *packet.Structure Reference *packet.Packet
} }
func NewPacketEditor(ref *packet.Structure) *PacketEditor { func NewPacketEditor(ref *packet.Packet) *PacketEditor {
metadata := NewMetadataPacket() metadata := NewMetadataPacket()
fields := container.NewGridWrap(fyne.NewSize(300, 200)) fields := container.NewGridWrap(fyne.NewSize(300, 200))
container := container.NewBorder(nil, nil, metadata.Representation, nil, container.NewVScroll(fields)) container := container.NewBorder(nil, nil, metadata.Representation, nil, container.NewVScroll(fields))

View File

@ -39,9 +39,9 @@ func CreatePacketFieldEditor(
elements := []fyne.CanvasObject{} elements := []fyne.CanvasObject{}
elements = append(elements, widget.NewLabel(ref.GetProtocolField().Name)) elements = append(elements, widget.NewLabel("TODO"))
if ed.ShowShortHints { if ed.ShowShortHints {
elements = append(elements, widget.NewLabel(ref.GetProtocolField().Regex)) // todo: implement real shorthints if feasible elements = append(elements, widget.NewLabel("TODO")) // todo: implement real shorthints if feasible
} }
// depending on the input stuff, entry for now // depending on the input stuff, entry for now

View File

@ -14,7 +14,7 @@ type PacketFileHandler struct {
changed bool changed bool
tab *container.TabItem tab *container.TabItem
Reference *packet.Structure Reference *packet.Packet
} }
func NewPacketFileHandler() *PacketFileHandler { func NewPacketFileHandler() *PacketFileHandler {

View File

@ -15,10 +15,10 @@ type ProtocolEditor struct {
Metadata *ProtocolMetadata Metadata *ProtocolMetadata
Fields []*FieldEditor Fields []*FieldEditor
Reference *protocol.ProtocolStructure Reference *protocol.Protocol
} }
func NewProtocolEditor(ref *protocol.ProtocolStructure) *ProtocolEditor { func NewProtocolEditor(ref *protocol.Protocol) *ProtocolEditor {
metadata := NewMetadataProtocol() metadata := NewMetadataProtocol()
fields := container.NewGridWrap(fyne.NewSize(300, 400)) fields := container.NewGridWrap(fyne.NewSize(300, 400))
container := container.NewBorder(nil, nil, metadata.Representation, nil, container.NewVScroll(fields)) container := container.NewBorder(nil, nil, metadata.Representation, nil, container.NewVScroll(fields))

View File

@ -17,7 +17,7 @@ type ProtocolFileHandler struct {
changed bool changed bool
tab *container.TabItem tab *container.TabItem
Reference *protocol.ProtocolStructure Reference *protocol.Protocol
} }
func NewProtocolFileHandler() *ProtocolFileHandler { func NewProtocolFileHandler() *ProtocolFileHandler {

View File

@ -1,20 +0,0 @@
package packet
import "gitea.mmo.to/ppForge/ppforge/protocol"
// FieldValue implements protocol.ProtocolFieldReferencer
type FieldValue struct {
fieldReference *protocol.Field
Value string
}
// GetProtocolField returns the protocol field
func (fv *FieldValue) GetProtocolField() *protocol.Field {
return fv.fieldReference
}
// SetProtocolField sets the protocl field
func (fv *FieldValue) SetProtocolField(pf *protocol.Field) {
fv.fieldReference = pf
}

View File

@ -1,26 +1,181 @@
package packet package packet
import "gitea.mmo.to/ppForge/ppforge/protocol" import (
"crypto/sha1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
)
// FieldValue implements protocol.ProtocolFieldReferencer
type FieldValue struct {
Field string
FieldNum int
Value string
}
// GetProtocolField returns the protocol field
func (fv *FieldValue) GetProtocolField() (string, int) {
return fv.Field, fv.FieldNum
}
// SetProtocolField sets the protocl field
func (fv *FieldValue) SetProtocolField(f string, fn int) {
fv.Field = f
fv.FieldNum = fn
}
// SetValue sets the value
func (fv *FieldValue) SetValue(v string) {
fv.Value = v
}
// Layer implements protocol.ProtocolReferencer // Layer implements protocol.ProtocolReferencer
type Layer struct { type Layer struct {
// needs a reference to a protocol
protocolReference *protocol.ProtocolStructure
ProtocolName string ProtocolName string
Values []FieldValue Values []FieldValue
} }
// Structure contains all layers of a packet // Packet contains all layers of a packet and the data in different formats
type Structure struct { type Packet struct {
MetaData Metadata MetaData Metadata
data []byte
Hex string
B64 string
Sha1 string
Layers []Layer Layers []Layer
} }
func (pl *Layer) GetProtocol() *protocol.ProtocolStructure { func NewPacketStructure() *Packet {
return pl.protocolReference p := Packet{}
return &p
}
func UpdateMetaData(
pack *Packet,
) {
// still empty
} }
func (pl *Layer) Setprotocol(ps *protocol.ProtocolStructure) { func NewPacketLayer() *Layer {
pl.protocolReference = ps p := Layer{}
return &p
}
func NewEmptyFieldValue() *FieldValue {
f := FieldValue{}
return &f
}
func NewFieldValue(
field string,
fieldnum int,
value string,
) *FieldValue {
f := FieldValue{
Value: value,
}
return &f
}
func (pack *Layer) AppendField(field *FieldValue) int {
i := len(pack.Values)
pack.Values = append(pack.Values, *field)
return i + 1
}
func (pack *Layer) AddField(index int, field *FieldValue) {
if len(pack.Values) == index {
pack.AppendField(field)
return
}
ret := make([]FieldValue, 0)
ret = append(ret, pack.Values[:index]...)
ret = append(ret, *field)
ret = append(ret, pack.Values[index:]...)
pack.Values = ret
}
func (pack *Packet) AppendLayer(layer *Layer) {
pack.Layers = append(pack.Layers, *layer)
}
func (pack *Packet) AddLayer(index int, layer *Layer) {
if len(pack.Layers) == index {
pack.AppendLayer(layer)
return
}
ret := make([]Layer, 0)
ret = append(ret, pack.Layers[:index]...)
ret = append(ret, *layer)
ret = append(ret, pack.Layers[index:]...)
pack.Layers = ret
}
func (pack *Layer) UpdateField(e int, field *FieldValue) {
pack.Values[e] = *field
}
func (pack *Packet) UpdateLayer(e int, layer *Layer) {
pack.Layers[e] = *layer
}
func (pack *Layer) RemoveField(e int) {
l := len(pack.Values) - 1
ret := make([]FieldValue, l)
ret = append(ret, pack.Values[:e]...)
ret = append(ret, pack.Values[e+1:]...)
pack.Values = ret
}
func (pack *Packet) RemoveLayer(e int) {
l := len(pack.Layers) - 1
ret := make([]Layer, l)
ret = append(ret, pack.Layers[:e]...)
ret = append(ret, pack.Layers[e+1:]...)
pack.Layers = ret
}
func (pack *Packet) Load(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
err = json.Unmarshal(data, pack)
pack.data, err = base64.StdEncoding.DecodeString(pack.B64)
if err != nil {
return err
}
if pack.Sha1 != fmt.Sprintf("%x", sha1.Sum(pack.data)) {
return errors.New("sha1sum does not match")
}
return err
}
func (pack *Packet) UpdateData() {
pack.Hex = fmt.Sprintf("%x", pack.data)
pack.B64 = base64.RawStdEncoding.EncodeToString(pack.data)
pack.Sha1 = fmt.Sprintf("%x", sha1.Sum(pack.data))
}
func (pack *Packet) ToJson() string {
pack.UpdateData()
data, err := json.MarshalIndent(*pack, "", " ")
if err != nil {
return ""
}
return string(data)
}
func (pack *Packet) Save(path string) error {
pack.UpdateData()
data, err := json.MarshalIndent(*pack, "", " ")
if err != nil {
return err
}
err = os.WriteFile(path, data, fs.ModeAppend)
return err
} }

28
packet/packet_test.go Normal file
View File

@ -0,0 +1,28 @@
package packet
import (
"testing"
"gitea.mmo.to/ppForge/ppforge/protocol"
)
func GenerateProtocol1() *protocol.Protocol {
return nil
}
func GenerateProtocol2() *protocol.Protocol {
return nil
}
func TestBinaryGeneration(t *testing.T) {
}
func TestJsonExport(t *testing.T) {
}
func TestJsonImport(t *testing.T) {
}

View File

@ -2,5 +2,6 @@ package packet
// Metadata struct is the absolute minimum of metadata // Metadata struct is the absolute minimum of metadata
type Metadata struct { type Metadata struct {
Name string Name string
Revision int
} }

View File

@ -1,123 +0,0 @@
package packetctl
import (
"encoding/json"
"io/fs"
"os"
"gitea.mmo.to/ppForge/ppforge/packet"
)
func NewPacketStructure() *packet.Structure {
p := packet.Structure{}
return &p
}
func UpdateMetaData(
pack *packet.Structure,
) {
// still empty
}
func NewPacketLayer() *packet.Layer {
p := packet.Layer{}
return &p
}
func NewEmptyFieldValue() *packet.FieldValue {
f := packet.FieldValue{}
return &f
}
func NewFieldValue(
value string,
) *packet.FieldValue {
f := packet.FieldValue{
Value: value,
}
return &f
}
func AppendField(pack *packet.Layer, field *packet.FieldValue) int {
i := len(pack.Values)
pack.Values = append(pack.Values, *field)
return i + 1
}
func AddField(pack *packet.Layer, index int, field *packet.FieldValue) {
if len(pack.Values) == index {
AppendField(pack, field)
return
}
ret := make([]packet.FieldValue, 0)
ret = append(ret, pack.Values[:index]...)
ret = append(ret, *field)
ret = append(ret, pack.Values[index:]...)
pack.Values = ret
}
func AppendLayer(pack *packet.Structure, layer *packet.Layer) {
pack.Layers = append(pack.Layers, *layer)
}
func Addlayer(pack *packet.Structure, index int, layer *packet.Layer) {
if len(pack.Layers) == index {
AppendLayer(pack, layer)
return
}
ret := make([]packet.Layer, 0)
ret = append(ret, pack.Layers[:index]...)
ret = append(ret, *layer)
ret = append(ret, pack.Layers[index:]...)
pack.Layers = ret
}
func UpdateField(pack *packet.Layer, e int, field *packet.FieldValue) {
pack.Values[e] = *field
}
func UpdateLayer(pack *packet.Structure, e int, layer *packet.Layer) {
pack.Layers[e] = *layer
}
func RemoveField(pack *packet.Layer, e int) {
l := len(pack.Values) - 1
ret := make([]packet.FieldValue, l)
ret = append(ret, pack.Values[:e]...)
ret = append(ret, pack.Values[e+1:]...)
pack.Values = ret
}
func RemoveLayer(pack *packet.Structure, e int) {
l := len(pack.Layers) - 1
ret := make([]packet.Layer, l)
ret = append(ret, pack.Layers[:e]...)
ret = append(ret, pack.Layers[e+1:]...)
pack.Layers = ret
}
func Load(pack *packet.Structure, path string) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
err = json.Unmarshal(data, pack)
return err
}
func ToJson(pack *packet.Structure) string {
data, err := json.MarshalIndent(*pack, "", " ")
if err != nil {
return ""
}
return string(data)
}
func Save(pack *packet.Structure, path string) error {
data, err := json.MarshalIndent(*pack, "", " ")
if err != nil {
return err
}
err = os.WriteFile(path, data, fs.ModeAppend)
return err
}

View File

@ -1,16 +0,0 @@
package protocol
const DOPVersion string = "1.0"
type DOPMeta struct {
// DOP metadata version 1.0
DOPVersion string
Name string
Version string
TCPIPLayer uint
OSILayer uint
ExtensionTo string
Description string
RequiredJSFunctions []string
LowerLayerIdentification map[string]string
}

View File

@ -3,13 +3,14 @@ package protocol
import "encoding/json" import "encoding/json"
type Field struct { type Field struct {
Name string // Name of the Field Name string // Name of the Field
Desc string // Lengthy description Desc string // Lengthy description
Regex string // Regex to recognize values Regex string // Regex to recognize values
Size int // Size in bits! Size int // Size in bits!
SubFields []Field // Possible sub-fields SubFields []Field // Possible sub-fields
Optional bool // Is this field required? Optional bool // Is this field required?
Payload bool // Is this field the payload or next protocol level? Payload bool // Is this field the payload or next protocol level?
JavaScript string
} }
type ProtocolFieldReferencer interface { type ProtocolFieldReferencer interface {
@ -24,3 +25,29 @@ func (f *Field) ToJson() string {
} }
return string(b) return string(b)
} }
func NewEmptyField() *Field {
f := Field{}
return &f
}
func NewField(
name string,
desc string,
regex string,
size int,
subfields []Field,
optional bool,
payload bool,
) *Field {
f := Field{
Name: name,
Desc: desc,
Regex: regex,
Size: size,
SubFields: subfields,
Optional: optional,
Payload: payload,
}
return &f
}

View File

@ -1,13 +1,107 @@
package protocol package protocol
type ProtocolStructure struct { import (
Metadata DOPMeta "encoding/json"
"fmt"
"io/fs"
"os"
)
type Protocol struct {
Metadata ProtocolMeta
Structure []*Field Structure []*Field
DefaultValues []DefaultValue DefaultValues []DefaultValue
JavaScript string JavaScript string
} }
type ProtocolReferencer interface { func (p Protocol) ToJson() string {
GetProtocol() *ProtocolStructure data, err := json.MarshalIndent(p, "", " ")
SetProtocol(prot *ProtocolStructure) if err != nil {
return ""
}
return string(data)
}
func NewProtocolStructure() *Protocol {
p := Protocol{}
return &p
}
func (prot *Protocol) AppendField(field Field) int {
i := len(prot.Structure)
prot.Structure = append(prot.Structure, &field)
return i + 1
}
func (prot *Protocol) AddField(index int, field *Field) {
if len(prot.Structure) == index {
prot.AppendField(*field)
return
}
ret := make([]*Field, 0)
ret = append(ret, prot.Structure[:index]...)
ret = append(ret, field)
ret = append(ret, prot.Structure[index:]...)
prot.Structure = ret
}
func (prot *Protocol) UpdateFieldByName(name string, field *Field) {
var fnd int = -1
for i, f := range prot.Structure {
if f.Name == name {
fnd = i
}
}
if fnd != -1 {
prot.Structure[fnd] = field
}
}
func (prot *Protocol) UpdateFieldByElement(element int, field *Field) {
prot.Structure[element] = field
}
func (prot *Protocol) RemoveFieldByName(name string) {
element := -1
for i, f := range prot.Structure {
if f.Name == name {
element = i
}
}
if element == -1 {
return
}
prot.RemoveFieldByElement(element)
}
func (prot *Protocol) RemoveFieldByElement(field int) {
ret := make([]*Field, 0)
for i, f := range prot.Structure {
if i != field {
fmt.Printf("appending %d, %s\n", i, f.ToJson())
ret = append(ret, f)
}
}
prot.Structure = ret
}
func (prot *Protocol) Load(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
err = json.Unmarshal(data, prot)
return err
}
func (prot *Protocol) Save(path string) error {
data, err := json.MarshalIndent(*prot, "", " ")
if err != nil {
return err
}
err = os.WriteFile(path, data, fs.ModeAppend)
return err
}
func LoadNew(path string) (*Protocol, error) {
prot := NewProtocolStructure()
err := prot.Load(path)
return prot, err
} }

View File

@ -1,10 +1,8 @@
package protocolctl package protocol
import ( import (
"fmt" "fmt"
"testing" "testing"
"gitea.mmo.to/ppForge/ppforge/protocol"
) )
func TestUpdateMetaData(t *testing.T) { func TestUpdateMetaData(t *testing.T) {
@ -30,7 +28,6 @@ func TestUpdateMetaData(t *testing.T) {
if prot.Metadata.Name != name || if prot.Metadata.Name != name ||
prot.Metadata.Description != desc || prot.Metadata.Description != desc ||
prot.Metadata.ExtensionTo != extensionTo || prot.Metadata.ExtensionTo != extensionTo ||
prot.Metadata.OSILayer != osilayer ||
prot.Metadata.TCPIPLayer != tcpiplayer || prot.Metadata.TCPIPLayer != tcpiplayer ||
prot.Metadata.Version != version || prot.Metadata.Version != version ||
prot.Metadata.LowerLayerIdentification != nil || prot.Metadata.LowerLayerIdentification != nil ||
@ -40,8 +37,8 @@ func TestUpdateMetaData(t *testing.T) {
} }
} }
func GenerateFields() []protocol.Field { func GenerateFields() []Field {
slc := make([]protocol.Field, 0) slc := make([]Field, 0)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
field := NewField( field := NewField(
fmt.Sprintf("testfield%d", i), fmt.Sprintf("testfield%d", i),
@ -57,11 +54,11 @@ func GenerateFields() []protocol.Field {
return slc return slc
} }
func GenerateStructure() *protocol.ProtocolStructure { func GenerateStructure() *Protocol {
p := NewProtocolStructure() p := NewProtocolStructure()
slc := GenerateFields() slc := GenerateFields()
for i, e := range slc { for i, e := range slc {
AppendField(p, e) p.AppendField(e)
fmt.Printf("%d %s\n", i, e.ToJson()) fmt.Printf("%d %s\n", i, e.ToJson())
} }
for i, e := range p.Structure { for i, e := range p.Structure {
@ -82,7 +79,7 @@ func TestFieldAppend(t *testing.T) {
false, false,
) )
p := NewProtocolStructure() p := NewProtocolStructure()
AppendField(p, *f) p.AppendField(*f)
if p.Structure[0].Name != "testfield" { if p.Structure[0].Name != "testfield" {
t.Log("Append failed.") t.Log("Append failed.")
t.Fail() t.Fail()
@ -110,7 +107,7 @@ func TestUpdateFieldByElement(t *testing.T) {
f := NewField( f := NewField(
"UpdatedField", "", "", 42, nil, false, true, "UpdatedField", "", "", 42, nil, false, true,
) )
UpdateFieldByElement(p, 5, f) p.UpdateFieldByElement(5, f)
for i, e := range p.Structure { for i, e := range p.Structure {
fmt.Printf("%d %s\n", i, e.ToJson()) fmt.Printf("%d %s\n", i, e.ToJson())
} }
@ -135,7 +132,7 @@ func TestUpdateFieldByElement(t *testing.T) {
*/ */
func TestRemoveFieldByElement(t *testing.T) { func TestRemoveFieldByElement(t *testing.T) {
p := GenerateStructure() p := GenerateStructure()
RemoveFieldByElement(p, 3) p.RemoveFieldByElement(3)
for i, e := range p.Structure { for i, e := range p.Structure {
fmt.Printf("%d %s\n", i, e.ToJson()) fmt.Printf("%d %s\n", i, e.ToJson())
} }
@ -147,5 +144,5 @@ func TestRemoveFieldByElement(t *testing.T) {
func TestToJson(t *testing.T) { func TestToJson(t *testing.T) {
p := GenerateStructure() p := GenerateStructure()
fmt.Print(ToJson(p)) fmt.Print(p.ToJson())
} }

28
protocol/protocolmeta.go Normal file
View File

@ -0,0 +1,28 @@
package protocol
type ProtocolMeta struct {
Name string
Revision uint
Version string
TCPIPLayer uint
ExtensionTo string
Description string
RequiredJSFunctions []string
LowerLayerIdentification map[string]string
}
func UpdateMetaData(
prot *Protocol,
name string,
version string,
tcpiplayer uint,
osilayer uint,
extensionTo string,
desc string,
) {
prot.Metadata.Name = name
prot.Metadata.Description = desc
prot.Metadata.ExtensionTo = extensionTo
prot.Metadata.Version = version
prot.Metadata.TCPIPLayer = tcpiplayer
}

View File

@ -1,147 +0,0 @@
package protocolctl
import (
"encoding/json"
"fmt"
"io/fs"
"os"
"gitea.mmo.to/ppForge/ppforge/protocol"
)
func NewProtocolStructure() *protocol.ProtocolStructure {
p := protocol.ProtocolStructure{}
return &p
}
func UpdateMetaData(
prot *protocol.ProtocolStructure,
name string,
version string,
tcpiplayer uint,
osilayer uint,
extensionTo string,
desc string,
) {
prot.Metadata.Name = name
prot.Metadata.Description = desc
prot.Metadata.ExtensionTo = extensionTo
prot.Metadata.Version = version
prot.Metadata.OSILayer = osilayer
prot.Metadata.TCPIPLayer = tcpiplayer
}
func NewEmptyField() *protocol.Field {
f := protocol.Field{}
return &f
}
func NewField(
name string,
desc string,
regex string,
size int,
subfields []protocol.Field,
optional bool,
payload bool,
) *protocol.Field {
f := protocol.Field{
Name: name,
Desc: desc,
Regex: regex,
Size: size,
SubFields: subfields,
Optional: optional,
Payload: payload,
}
return &f
}
func AppendField(prot *protocol.ProtocolStructure, field protocol.Field) int {
i := len(prot.Structure)
prot.Structure = append(prot.Structure, &field)
return i + 1
}
func AddField(prot *protocol.ProtocolStructure, index int, field *protocol.Field) {
if len(prot.Structure) == index {
AppendField(prot, *field)
return
}
ret := make([]*protocol.Field, 0)
ret = append(ret, prot.Structure[:index]...)
ret = append(ret, field)
ret = append(ret, prot.Structure[index:]...)
prot.Structure = ret
}
func UpdateFieldByName(prot *protocol.ProtocolStructure, name string, field *protocol.Field) {
var fnd int = -1
for i, f := range prot.Structure {
if f.Name == name {
fnd = i
}
}
if fnd != -1 {
prot.Structure[fnd] = field
}
}
func UpdateFieldByElement(prot *protocol.ProtocolStructure, element int, field *protocol.Field) {
prot.Structure[element] = field
}
func RemoveFieldByName(prot *protocol.ProtocolStructure, name string) {
element := -1
for i, f := range prot.Structure {
if f.Name == name {
element = i
}
}
if element == -1 {
return
}
RemoveFieldByElement(prot, element)
}
func RemoveFieldByElement(prot *protocol.ProtocolStructure, field int) {
ret := make([]*protocol.Field, 0)
for i, f := range prot.Structure {
if i != field {
fmt.Printf("appending %d, %s\n", i, f.ToJson())
ret = append(ret, f)
}
}
prot.Structure = ret
}
func Load(prot *protocol.ProtocolStructure, path string) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
err = json.Unmarshal(data, prot)
return err
}
func LoadNew(path string) (*protocol.ProtocolStructure, error) {
prot := NewProtocolStructure()
err := Load(prot, path)
return prot, err
}
func ToJson(prot *protocol.ProtocolStructure) string {
data, err := json.MarshalIndent(*prot, "", " ")
if err != nil {
return ""
}
return string(data)
}
func Save(prot *protocol.ProtocolStructure, path string) error {
data, err := json.MarshalIndent(*prot, "", " ")
if err != nil {
return err
}
err = os.WriteFile(path, data, fs.ModeAppend)
return err
}

View File

@ -0,0 +1,34 @@
{
"Metadata": {
"Revision": 2,
"Name": "blabla",
"Version": "",
"TCPIPLayer": 0,
"ExtensionTo": "",
"Description": "",
"RequiredJSFunctions": null,
"LowerLayerIdentification": null
},
"Structure": [
{
"Name": "asdfasdf",
"Desc": "",
"Regex": "",
"Size": 8,
"SubFields": null,
"Optional": false,
"Payload": false
},
{
"Name": "asdfasdfasdf",
"Desc": "test",
"Regex": "",
"Size": 24,
"SubFields": null,
"Optional": false,
"Payload": false
}
],
"DefaultValues": null,
"JavaScript": ""
}

View File

@ -0,0 +1,61 @@
{
"Metadata": {
"Revision": 1,
"Name": "blah",
"Version": "",
"TCPIPLayer": 0,
"ExtensionTo": "",
"Description": "",
"RequiredJSFunctions": null,
"LowerLayerIdentification": null
},
"Structure": [
{
"Name": "test",
"Desc": "",
"Regex": "",
"Size": 32,
"SubFields": null,
"Optional": false,
"Payload": false
},
{
"Name": "",
"Desc": "",
"Regex": "",
"Size": 32,
"SubFields": null,
"Optional": false,
"Payload": false
},
{
"Name": "",
"Desc": "",
"Regex": "",
"Size": 8,
"SubFields": null,
"Optional": false,
"Payload": false
},
{
"Name": "",
"Desc": "",
"Regex": "",
"Size": 4,
"SubFields": null,
"Optional": false,
"Payload": false
},
{
"Name": "",
"Desc": "",
"Regex": "",
"Size": 20,
"SubFields": null,
"Optional": false,
"Payload": false
}
],
"DefaultValues": null,
"JavaScript": ""
}

View File

@ -0,0 +1,25 @@
{
"Metadata": {
"Revision": 1,
"Name": "test",
"Version": "",
"TCPIPLayer": 0,
"ExtensionTo": "",
"Description": "test",
"RequiredJSFunctions": null,
"LowerLayerIdentification": null
},
"Structure": [
{
"Name": "test",
"Desc": "test",
"Regex": "",
"Size": 128,
"SubFields": null,
"Optional": false,
"Payload": false
}
],
"DefaultValues": null,
"JavaScript": ""
}