Skip to content
Snippets Groups Projects
follow.go 10.1 KiB
Newer Older
Jono Wenger's avatar
Jono Wenger committed
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 xx foundation                                             //
Jono Wenger's avatar
Jono Wenger committed
//                                                                            //
// Use of this source code is governed by a license that can be found in the  //
// LICENSE file.                                                              //
Jono Wenger's avatar
Jono Wenger committed
////////////////////////////////////////////////////////////////////////////////

//go:build js && wasm

Jono Wenger's avatar
Jono Wenger committed
package wasm
Jono Wenger's avatar
Jono Wenger committed

import (
Jono Wenger's avatar
Jono Wenger committed
	"gitlab.com/elixxir/xxdk-wasm/utils"
Jono Wenger's avatar
Jono Wenger committed
	"syscall/js"
)

// StartNetworkFollower kicks off the tracking of the network. It starts long-
// running network threads and returns an object for checking state and
// stopping those threads.
//
// Call this when returning from sleep and close when going back to sleep.
//
// These threads may become a significant drain on battery when offline, ensure
// they are stopped if there is no internet access.
//
// Threads Started:
//   - Network Follower (/network/follow.go)
//     tracks the network events and hands them off to workers for handling.
//   - Historical Round Retrieval (/network/rounds/historical.go)
//     retrieves data about rounds that are too old to be stored by the client.
//	 - Message Retrieval Worker Group (/network/rounds/retrieve.go)
//	   requests all messages in a given round from the gateway of the last
//	   nodes.
//	 - Message Handling Worker Group (/network/message/handle.go)
//	   decrypts and partitions messages when signals via the Switchboard.
//	 - Health Tracker (/network/health),
//	   via the network instance, tracks the state of the network.
//	 - Garbled Messages (/network/message/garbled.go)
//	   can be signaled to check all recent messages that could be decoded. It
//	   uses a message store on disk for persistence.
//	 - Critical Messages (/network/message/critical.go)
//	   ensures all protocol layer mandatory messages are sent. It uses a message
//	   store on disk for persistence.
//	 - KeyExchange Trigger (/keyExchange/trigger.go)
//	   responds to sent rekeys and executes them.
//   - KeyExchange Confirm (/keyExchange/confirm.go)
//	   responds to confirmations of successful rekey operations.
//   - Auth Callback (/auth/callback.go)
//     handles both auth confirm and requests.
//
// Parameters:
//  - args[0] - Timeout when stopping threads in milliseconds (int).
Jono Wenger's avatar
Jono Wenger committed
//
// Returns:
//  - Throws a TypeError if starting the network follower fails.
Jono Wenger's avatar
Jono Wenger committed
func (c *Cmix) StartNetworkFollower(_ js.Value, args []js.Value) interface{} {
	err := c.api.StartNetworkFollower(args[0].Int())
	if err != nil {
Jono Wenger's avatar
Jono Wenger committed
		utils.Throw(utils.TypeError, err)
Jono Wenger's avatar
Jono Wenger committed
		return nil
Jono Wenger's avatar
Jono Wenger committed
	}

	return nil
}

// StopNetworkFollower stops the network follower if it is running.
//
// If the network follower is running and this fails, the [Cmix] object will
Jono Wenger's avatar
Jono Wenger committed
// most likely be in an unrecoverable state and need to be trashed.
//
// Returns:
//  - Throws a TypeError if the follower is in the wrong state to stop or if it
//    fails to stop.
Jono Wenger's avatar
Jono Wenger committed
func (c *Cmix) StopNetworkFollower(js.Value, []js.Value) interface{} {
	err := c.api.StopNetworkFollower()
	if err != nil {
Jono Wenger's avatar
Jono Wenger committed
		utils.Throw(utils.TypeError, err)
Jono Wenger's avatar
Jono Wenger committed
		return nil
Jono Wenger's avatar
Jono Wenger committed
	}

	return nil
}

// WaitForNetwork will block until either the network is healthy or the passed
// timeout is reached. It will return true if the network is healthy.
//
// Parameters:
//  - args[0] - Timeout when stopping threads in milliseconds (int).
Jono Wenger's avatar
Jono Wenger committed
//
Jono Wenger's avatar
Jono Wenger committed
// Returns a promise:
//  - A promise that resolves if the network is healthy and rejects if the
//    network is not healthy.
Jono Wenger's avatar
Jono Wenger committed
func (c *Cmix) WaitForNetwork(_ js.Value, args []js.Value) interface{} {
Jono Wenger's avatar
Jono Wenger committed
	promiseFn := func(resolve, reject func(args ...interface{}) js.Value) {
		if c.api.WaitForNetwork(args[0].Int()) {
			resolve()
		} else {
			reject()
		}
	}

	return utils.CreatePromise(promiseFn)
Jono Wenger's avatar
Jono Wenger committed
}

// NetworkFollowerStatus gets the state of the network follower. It returns a
// status with the following values:
//  Stopped  - 0
//  Running  - 2000
//  Stopping - 3000
//
// Returns:
//  - Network status code (int).
Jono Wenger's avatar
Jono Wenger committed
func (c *Cmix) NetworkFollowerStatus(js.Value, []js.Value) interface{} {
	return c.api.NetworkFollowerStatus()
}

// GetNodeRegistrationStatus returns the current state of node registration.
//
// Returns:
//  - JSON of [bindings.NodeRegistrationReport] containing the number of nodes
//    that the user is registered with and the number of nodes present in the
//    NDF.
Jono Wenger's avatar
Jono Wenger committed
//  - An error if it cannot get the node registration status. The most likely
//    cause is that the network is unhealthy.
func (c *Cmix) GetNodeRegistrationStatus(js.Value, []js.Value) interface{} {
	b, err := c.api.GetNodeRegistrationStatus()
	if err != nil {
Jono Wenger's avatar
Jono Wenger committed
		utils.Throw(utils.TypeError, err)
Jono Wenger's avatar
Jono Wenger committed
		return nil
Jono Wenger's avatar
Jono Wenger committed
	}

Jono Wenger's avatar
Jono Wenger committed
	return utils.CopyBytesToJS(b)
Jono Wenger's avatar
Jono Wenger committed
}

// HasRunningProcessies checks if any background threads are running and returns
// true if one or more are.
//
// This is meant to be used when [NetworkFollowerStatus] returns Stopping. Due
// to the handling of comms on iOS, where the OS can block indefinitely, it may
// not enter the stopped state appropriately. This can be used instead.
Jono Wenger's avatar
Jono Wenger committed
//
// Returns:
//  - True if there are running processes (boolean).
Jono Wenger's avatar
Jono Wenger committed
func (c *Cmix) HasRunningProcessies(js.Value, []js.Value) interface{} {
	return c.api.HasRunningProcessies()
}

// IsHealthy returns true if the network is read to be in a healthy state where
// messages can be sent.
//
// Returns:
//  - True if the network is healthy (boolean).
Jono Wenger's avatar
Jono Wenger committed
func (c *Cmix) IsHealthy(js.Value, []js.Value) interface{} {
	return c.api.IsHealthy()
}

// GetRunningProcesses returns the names of all running processes at the time
// of this call. Note that this list may change and is subject to race
// conditions if multiple threads are in the process of starting or stopping.
//
// Returns:
//  - JSON of strings (Uint8Array).
//
// JSON Example:
//  {
//    "FileTransfer{BatchBuilderThread, FilePartSendingThread#0, FilePartSendingThread#1, FilePartSendingThread#2, FilePartSendingThread#3}",
//    "MessageReception Worker 0"
//  }
func (c *Cmix) GetRunningProcesses(js.Value, []js.Value) interface{} {
	list, err := c.api.GetRunningProcesses()
	if err != nil {
		utils.Throw(utils.TypeError, err)
		return nil
	}

	return utils.CopyBytesToJS(list)
}

Jono Wenger's avatar
Jono Wenger committed
// networkHealthCallback adheres to the [bindings.NetworkHealthCallback]
// interface.
type networkHealthCallback struct {
	callback func(args ...interface{}) js.Value
}

// Callback receives notification if network health changes.
//
// Parameters:
//  - health - Returns true if the network is healthy and false otherwise
//    (boolean).
Jono Wenger's avatar
Jono Wenger committed
func (nhc *networkHealthCallback) Callback(health bool) { nhc.callback(health) }

// AddHealthCallback adds a callback that gets called whenever the network
// health changes. Returns a registration ID that can be used to unregister.
//
// Parameters:
//  - args[0] - Javascript object that has functions that implement the
//    [bindings.NetworkHealthCallback] interface.
Jono Wenger's avatar
Jono Wenger committed
//
// Returns:
//  - A registration ID that can be used to unregister the callback (int).
Jono Wenger's avatar
Jono Wenger committed
func (c *Cmix) AddHealthCallback(_ js.Value, args []js.Value) interface{} {
	return c.api.AddHealthCallback(
Jono Wenger's avatar
Jono Wenger committed
		&networkHealthCallback{utils.WrapCB(args[0], "Callback")})
Jono Wenger's avatar
Jono Wenger committed
}

// RemoveHealthCallback removes a health callback using its registration ID.
//
// Parameters:
//  - args[0] - Callback registration ID (int).
Jono Wenger's avatar
Jono Wenger committed
func (c *Cmix) RemoveHealthCallback(_ js.Value, args []js.Value) interface{} {
	c.api.RemoveHealthCallback(int64(args[0].Int()))
	return nil
}

// clientError adheres to the [bindings.ClientError] interface.
type clientError struct {
	report func(args ...interface{}) js.Value
}

// Report handles errors from the network follower threads.
Jono Wenger's avatar
Jono Wenger committed
func (ce *clientError) Report(source, message, trace string) {
	ce.report(source, message, trace)
}

// RegisterClientErrorCallback registers the callback to handle errors from the
// long-running threads controlled by StartNetworkFollower and
// StopNetworkFollower.
//
// Parameters:
//  - args[0] - Javascript object that has functions that implement the
Jono Wenger's avatar
Jono Wenger committed
//    [bindings.ClientError] interface.
Jono Wenger's avatar
Jono Wenger committed
func (c *Cmix) RegisterClientErrorCallback(_ js.Value, args []js.Value) interface{} {
	c.api.RegisterClientErrorCallback(
		&clientError{utils.WrapCB(args[0], "Report")})
Jono Wenger's avatar
Jono Wenger committed
	return nil
}
Jono Wenger's avatar
Jono Wenger committed

// trackServicesCallback adheres to the [bindings.TrackServicesCallback]
// interface.
type trackServicesCallback struct {
	callback func(args ...interface{}) js.Value
}

// Callback is the callback for [Cmix.TrackServices]. This will pass to the user
// a JSON-marshalled list of backend services. If there was an error retrieving
// or marshalling the service list, there is an error for the second parameter,
// which will be non-null.
//
// Parameters:
//  - marshalData - Returns the JSON of [message.ServiceList] (Uint8Array).
//  - err - Returns an error on failure (Error).
//
// Example JSON:
//  [
//    {
//      "Id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", // bytes of id.ID encoded as base64 string
//      "Services": [
//        {
//          "Identifier": "AQID",                             // bytes encoded as base64 string
//          "Tag": "TestTag 1",                               // string
//          "Metadata": "BAUG"                                // bytes encoded as base64 string
//        }
//      ]
//    },
//    {
//      "Id": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD",
//      "Services": [
//        {
//          "Identifier": "AQID",
//          "Tag": "TestTag 2",
//          "Metadata": "BAUG"
//        }
//      ]
//    },
//  ]
Jono Wenger's avatar
Jono Wenger committed
func (tsc *trackServicesCallback) Callback(marshalData []byte, err error) {
	tsc.callback(utils.CopyBytesToJS(marshalData), utils.JsTrace(err))
}

// TrackServices will return, via a callback, the list of services that the
// backend keeps track of, which is formally referred to as a
// [message.ServiceList]. This may be passed into other bindings call that may
// need context on the available services for this client.
//
// Parameters:
//  - args[0] - Javascript object that has functions that implement the
//    [bindings.TrackServicesCallback] interface.
func (c *Cmix) TrackServices(_ js.Value, args []js.Value) interface{} {
	c.api.TrackServices(
		&trackServicesCallback{utils.WrapCB(args[0], "Callback")})
	return nil
}