5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-12-23 13:25:39 +00:00
yggdrasil-go/src/core/nodeinfo.go

174 lines
4.2 KiB
Go
Raw Normal View History

package core
2021-05-16 18:52:52 +00:00
import (
2021-05-16 20:27:51 +00:00
"encoding/hex"
2021-05-16 18:52:52 +00:00
"encoding/json"
"errors"
"fmt"
2021-05-16 18:52:52 +00:00
"runtime"
"time"
iwt "github.com/Arceliar/ironwood/types"
2021-05-16 18:52:52 +00:00
"github.com/Arceliar/phony"
"github.com/yggdrasil-network/yggdrasil-go/src/version"
)
type nodeinfo struct {
phony.Inbox
2021-05-23 16:58:52 +00:00
proto *protoHandler
2022-10-15 14:42:52 +00:00
myNodeInfo json.RawMessage
2021-05-16 18:52:52 +00:00
callbacks map[keyArray]nodeinfoCallback
}
type nodeinfoCallback struct {
2022-10-15 14:42:52 +00:00
call func(nodeinfo json.RawMessage)
2021-05-16 18:52:52 +00:00
created time.Time
}
// Initialises the nodeinfo cache/callback maps, and starts a goroutine to keep
// the cache/callback maps clean of stale entries
2021-05-23 16:58:52 +00:00
func (m *nodeinfo) init(proto *protoHandler) {
2021-05-16 18:52:52 +00:00
m.Act(nil, func() {
2021-05-23 16:58:52 +00:00
m._init(proto)
2021-05-16 18:52:52 +00:00
})
}
2021-05-23 16:58:52 +00:00
func (m *nodeinfo) _init(proto *protoHandler) {
m.proto = proto
2021-05-16 18:52:52 +00:00
m.callbacks = make(map[keyArray]nodeinfoCallback)
m._cleanup()
}
func (m *nodeinfo) _cleanup() {
for boxPubKey, callback := range m.callbacks {
if time.Since(callback.created) > time.Minute {
delete(m.callbacks, boxPubKey)
}
}
time.AfterFunc(time.Second*30, func() {
m.Act(nil, m._cleanup)
})
}
2022-10-15 14:42:52 +00:00
func (m *nodeinfo) _addCallback(sender keyArray, call func(nodeinfo json.RawMessage)) {
2021-05-16 18:52:52 +00:00
m.callbacks[sender] = nodeinfoCallback{
created: time.Now(),
call: call,
}
}
// Handles the callback, if there is one
2022-10-15 14:42:52 +00:00
func (m *nodeinfo) _callback(sender keyArray, nodeinfo json.RawMessage) {
2021-05-16 18:52:52 +00:00
if callback, ok := m.callbacks[sender]; ok {
2021-05-16 20:27:51 +00:00
callback.call(nodeinfo)
2021-05-16 18:52:52 +00:00
delete(m.callbacks, sender)
}
}
2022-10-15 14:42:52 +00:00
func (m *nodeinfo) _getNodeInfo() json.RawMessage {
2021-05-16 18:52:52 +00:00
return m.myNodeInfo
}
// Set the current node's nodeinfo
2022-10-15 14:42:52 +00:00
func (m *nodeinfo) setNodeInfo(given map[string]interface{}, privacy bool) (err error) {
2021-05-16 18:52:52 +00:00
phony.Block(m, func() {
err = m._setNodeInfo(given, privacy)
})
return
}
2022-10-15 14:42:52 +00:00
func (m *nodeinfo) _setNodeInfo(given map[string]interface{}, privacy bool) error {
newnodeinfo := make(map[string]interface{}, len(given))
for k, v := range given {
newnodeinfo[k] = v
2021-05-16 18:52:52 +00:00
}
if !privacy {
2022-10-15 14:42:52 +00:00
newnodeinfo["buildname"] = version.BuildName()
newnodeinfo["buildversion"] = version.BuildVersion()
newnodeinfo["buildplatform"] = runtime.GOOS
newnodeinfo["buildarch"] = runtime.GOARCH
2021-05-16 18:52:52 +00:00
}
newjson, err := json.Marshal(newnodeinfo)
2022-10-15 14:42:52 +00:00
switch {
case err != nil:
return fmt.Errorf("NodeInfo marshalling failed: %w", err)
case len(newjson) > 16384:
return fmt.Errorf("NodeInfo exceeds max length of 16384 bytes")
default:
2021-05-16 18:52:52 +00:00
m.myNodeInfo = newjson
return nil
}
}
2022-10-15 14:42:52 +00:00
func (m *nodeinfo) sendReq(from phony.Actor, key keyArray, callback func(nodeinfo json.RawMessage)) {
2021-05-16 18:52:52 +00:00
m.Act(from, func() {
m._sendReq(key, callback)
})
}
2022-10-15 14:42:52 +00:00
func (m *nodeinfo) _sendReq(key keyArray, callback func(nodeinfo json.RawMessage)) {
2021-05-16 18:52:52 +00:00
if callback != nil {
m._addCallback(key, callback)
}
_, _ = m.proto.core.PacketConn.WriteTo([]byte{typeSessionProto, typeProtoNodeInfoRequest}, iwt.Addr(key[:]))
2021-05-16 18:52:52 +00:00
}
func (m *nodeinfo) handleReq(from phony.Actor, key keyArray) {
m.Act(from, func() {
m._sendRes(key)
})
}
2022-10-15 14:42:52 +00:00
func (m *nodeinfo) handleRes(from phony.Actor, key keyArray, info json.RawMessage) {
2021-05-16 18:52:52 +00:00
m.Act(from, func() {
m._callback(key, info)
})
}
func (m *nodeinfo) _sendRes(key keyArray) {
2021-05-23 16:58:52 +00:00
bs := append([]byte{typeSessionProto, typeProtoNodeInfoResponse}, m._getNodeInfo()...)
_, _ = m.proto.core.PacketConn.WriteTo(bs, iwt.Addr(key[:]))
2021-05-16 18:52:52 +00:00
}
2021-05-16 20:27:51 +00:00
// Admin socket stuff
type GetNodeInfoRequest struct {
Key string `json:"key"`
}
type GetNodeInfoResponse map[string]json.RawMessage
2021-05-16 20:27:51 +00:00
func (m *nodeinfo) nodeInfoAdminHandler(in json.RawMessage) (interface{}, error) {
var req GetNodeInfoRequest
if err := json.Unmarshal(in, &req); err != nil {
return nil, err
}
if req.Key == "" {
return nil, fmt.Errorf("No remote public key supplied")
}
2021-05-16 20:27:51 +00:00
var key keyArray
var kbs []byte
var err error
if kbs, err = hex.DecodeString(req.Key); err != nil {
return nil, fmt.Errorf("Failed to decode public key: %w", err)
2021-05-16 20:27:51 +00:00
}
copy(key[:], kbs)
ch := make(chan []byte, 1)
2022-10-15 14:42:52 +00:00
m.sendReq(nil, key, func(info json.RawMessage) {
2021-05-16 20:27:51 +00:00
ch <- info
})
timer := time.NewTimer(6 * time.Second)
defer timer.Stop()
select {
case <-timer.C:
return nil, errors.New("Timed out waiting for response")
2021-05-16 20:27:51 +00:00
case info := <-ch:
2021-05-16 20:55:30 +00:00
var msg json.RawMessage
if err := msg.UnmarshalJSON(info); err != nil {
return nil, err
}
key := hex.EncodeToString(kbs[:])
res := GetNodeInfoResponse{key: msg}
2021-05-16 20:27:51 +00:00
return res, nil
}
}