Anton Tarasenko
3 years ago
9 changed files with 733 additions and 358 deletions
@ -1,88 +0,0 @@
|
||||
class AvariceClient extends AcediaObject; |
||||
|
||||
enum AvariceClientState |
||||
{ |
||||
ACS_Waiting, |
||||
ACS_ReadingID, |
||||
ACS_ReadingLength, |
||||
ACS_ReadingPayload, |
||||
ACS_Invalid |
||||
}; |
||||
|
||||
var private int currentID; |
||||
var private int currentMessageLength; |
||||
var private array<byte> currentPayload; |
||||
|
||||
var private AvariceClientState currentState; |
||||
var private int bytesLeftToRead; |
||||
var private byte buffer[255]; |
||||
var private array<byte> longBuffer; |
||||
var private int pendingBytes; |
||||
|
||||
public final function PushByte(byte nextByte) |
||||
{ |
||||
if (nextByte == 0) |
||||
{ |
||||
if (bytesLeftToRead > 0) |
||||
{ |
||||
// ACK for short message (with id) |
||||
} |
||||
currentState = ACS_Waiting; |
||||
ResetBuffer(); |
||||
return; |
||||
} |
||||
else if (currentState == ACS_Invalid) |
||||
{ |
||||
// ACK of invalid message's end |
||||
return; |
||||
} |
||||
else if (currentState == ACS_Waiting) |
||||
{ |
||||
currentID = nextByte; |
||||
currentID = currentID << 8; |
||||
currentState = ACS_ReadingID; |
||||
} |
||||
else if (currentState == ACS_ReadingID) |
||||
{ |
||||
currentID += nextByte; |
||||
currentState = ACS_ReadingLength; |
||||
bytesLeftToRead = 2; |
||||
} |
||||
else if (currentState == ACS_ReadingLength) |
||||
{ |
||||
bytesLeftToRead -= 1; |
||||
if (bytesLeftToRead > 0) |
||||
{ |
||||
currentMessageLength = nextByte; |
||||
currentMessageLength = currentMessageLength << 8; |
||||
} |
||||
else |
||||
{ |
||||
currentMessageLength += nextByte; |
||||
currentState = ACS_ReadingPayload; |
||||
bytesLeftToRead = currentMessageLength; |
||||
} |
||||
} |
||||
else if (currentState == ACS_ReadingPayload) |
||||
{ |
||||
currentPayload[currentPayload.length] = nextByte; |
||||
// Decode payload into `AvariceMessage` |
||||
// Send messages via Acedia's signals |
||||
bytesLeftToRead -= 1; |
||||
if (bytesLeftToRead == 0) |
||||
{ |
||||
currentState = ACS_Waiting; |
||||
// ACK into buffer |
||||
} |
||||
} |
||||
} |
||||
|
||||
private final function ResetBuffer() |
||||
{ |
||||
pendingBytes = 0; |
||||
longBuffer.length = 0; |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
@ -0,0 +1,437 @@
|
||||
/** |
||||
* Provide interface for the connection to Avarice application. |
||||
* It's parameters are defined in Acedia's config. |
||||
* Class provides methods to obtain its configuration information |
||||
* (name, address, port), methods to check and change the status of connection, |
||||
* signals to handle arriving messages and ways to send messages back. |
||||
* Copyright 2021 Anton Tarasenko |
||||
*------------------------------------------------------------------------------ |
||||
* This file is part of Acedia. |
||||
* |
||||
* Acedia is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* Acedia is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class AvariceLink extends AcediaObject; |
||||
|
||||
/** |
||||
* Objects of this class are supposed to be obtained via the |
||||
* `AvariceAPI.GetLink()` method. Available links are automatically initialized |
||||
* based on the configs and their parameters cannot be changed. |
||||
* It is also possible to spawn a link of your own by creating an object of |
||||
* this class (`AvariceLink`) and calling `Initialize()` method with |
||||
* appropriate parameters. To start the link then simply call `StartUp()`. |
||||
* But such links will not appear in the list of available links in |
||||
* `AvariceAPI`. |
||||
*/ |
||||
|
||||
// Actual work of dealing with network input/output is done in |
||||
// the `AvariceTcpStream` `Actor` class that is stored inside this reference |
||||
var private NativeActorRef tcpStream; |
||||
|
||||
// `tcpStream` communicates with this class by informing it about specific |
||||
// events. This enum describes all of their types. |
||||
enum AvariceNetworkMessage |
||||
{ |
||||
// Connection with Avarice established - can happen several times in case |
||||
// connection is interrupted |
||||
ANM_Connected, |
||||
// We have lost connection with Avarice, but normally will attempt to |
||||
// reconnect back |
||||
ANM_Disconnected, |
||||
// JSON message received |
||||
ANM_Message, |
||||
// Connection died: either was manually closed, host address could not |
||||
// be resolved or invalid data was received from Avarice |
||||
ANM_Death |
||||
}; |
||||
|
||||
// Name of this link, specified in the config |
||||
var private Text linkName; |
||||
// Host of the Avarice instance we are connecting to |
||||
var private Text linkHost; |
||||
// Port used by the Avarice instance we are connecting to |
||||
var private int linkPort; |
||||
|
||||
var private SimpleSignal onConnectedSignal; |
||||
var private SimpleSignal onDisconnectedSignal; |
||||
var private SimpleSignal onDeathSignal; |
||||
// We want to have a separate signal for each message "service", since most |
||||
// users of `AvariceLink` would only care about one particular service. |
||||
// To achieve that we use this array as a "service name" <-> "signal" map. |
||||
var private AssociativeArray serviceSignalMap; |
||||
|
||||
var private const int TSERVICE_PREFIX, TTYPE_PREFIX; |
||||
var private const int TPARAMS_PREFIX, TMESSAGE_SUFFIX; |
||||
|
||||
var private LoggerAPI.Definition fatalCannotSpawn; |
||||
|
||||
protected function Constructor() |
||||
{ |
||||
onConnectedSignal = SimpleSignal(_.memory.Allocate(class'SimpleSignal')); |
||||
onDisconnectedSignal = SimpleSignal(_.memory.Allocate(class'SimpleSignal')); |
||||
onDeathSignal = SimpleSignal(_.memory.Allocate(class'SimpleSignal')); |
||||
serviceSignalMap = _.collections.EmptyAssociativeArray(); |
||||
} |
||||
|
||||
protected function Finalizer() |
||||
{ |
||||
local Actor storedStream; |
||||
_.memory.Free(onConnectedSignal); |
||||
_.memory.Free(onDisconnectedSignal); |
||||
_.memory.Free(onDeathSignal); |
||||
_.memory.Free(serviceSignalMap); |
||||
_.memory.Free(linkName); |
||||
_.memory.Free(linkHost); |
||||
onConnectedSignal = none; |
||||
onDisconnectedSignal = none; |
||||
onDeathSignal = none; |
||||
serviceSignalMap = none; |
||||
linkName = none; |
||||
linkHost = none; |
||||
linkPort = 0; |
||||
if (tcpStream == none) { |
||||
return; |
||||
} |
||||
storedStream = tcpStream.Get(); |
||||
if (storedStream != none) { |
||||
storedStream.Destroy(); |
||||
} |
||||
tcpStream.FreeSelf(); |
||||
tcpStream = none; |
||||
} |
||||
|
||||
/** |
||||
* Initializes this caller `AvariceLink` with config data. |
||||
* |
||||
* Can only successfully (for that `name` and `host` must not be `none`) |
||||
* be called once. |
||||
* |
||||
* @param name Alias (case-insensitive) of caller `AvariceLink`. |
||||
* Must not be `none`. |
||||
* @param host Host of the Avarice instance that caller `AvariceLink` is |
||||
* connecting to. Must not be `none`. |
||||
* @param name Port used by the Avarice instance that caller `AvariceLink` |
||||
* is connecting to. |
||||
*/ |
||||
public final function Initialize(Text name, Text host, int port) |
||||
{ |
||||
if (tcpStream != none) return; |
||||
if (name == none) return; |
||||
if (host == none) return; |
||||
|
||||
linkName = name.Copy(); |
||||
linkHost = host.Copy(); |
||||
linkPort = port; |
||||
tcpStream = _.unreal.ActorRef(none); |
||||
} |
||||
|
||||
/** |
||||
* Signal that will be emitted whenever caller `AvariceLink` connects to |
||||
* Avarice. This event can be emitted multiple times if case link temporarily |
||||
* loses it's TCP connection or if connection is killed off due to errors |
||||
* (or manually). |
||||
* |
||||
* [Signature] |
||||
* void <slot>() |
||||
*/ |
||||
/* SIGNAL */ |
||||
public final function SimpleSlot OnConnected(AcediaObject receiver) |
||||
{ |
||||
return SimpleSlot(onConnectedSignal.NewSlot(receiver)); |
||||
} |
||||
|
||||
/** |
||||
* Signal that will be emitted whenever caller `AvariceLink` disconnects from |
||||
* Avarice. Disconnects can temporarily be cause by network issue and |
||||
* `AvariceLink` will attempt to restore it's connection. To detect when |
||||
* connection was permanently severed use `OnDeath` signal instead. |
||||
* |
||||
* [Signature] |
||||
* void <slot>() |
||||
*/ |
||||
/* SIGNAL */ |
||||
public final function SimpleSlot OnDisconnected(AcediaObject receiver) |
||||
{ |
||||
return SimpleSlot(onDisconnectedSignal.NewSlot(receiver)); |
||||
} |
||||
|
||||
/** |
||||
* Signal that will be emitted whenever connection is closed and dropped: |
||||
* either due to bein unable to resolve host's address, receiving incorrect |
||||
* input from Avarice or someone manually closing it. |
||||
* |
||||
* [Signature] |
||||
* void <slot>() |
||||
*/ |
||||
/* SIGNAL */ |
||||
public final function SimpleSlot OnDeath(AcediaObject receiver) |
||||
{ |
||||
return SimpleSlot(onDeathSignal.NewSlot(receiver)); |
||||
} |
||||
|
||||
/** |
||||
* Signal that will be emitted whenever caller `AvariceLink` disconnects from |
||||
* Avarice. Disconnects can temporarily be cause by network issue and |
||||
* `AvariceLink` will attempt to restore it's connection. To detect when |
||||
* connection was permanently severed use `OnDeath` signal instead. |
||||
* |
||||
* @param service Name of the service, whos messages one wants to receive. |
||||
* `none` will be treated as an empty `Text`. |
||||
* |
||||
* [Signature] |
||||
* void <slot>(AvariceLink link, AvariceMessage message) |
||||
* @param link Link that has received message. |
||||
* @param message Received message. |
||||
* Can be any JSON-compatible value (see `JSONAPI.IsCompatible()` |
||||
* for more information). |
||||
*/ |
||||
/* SIGNAL */ |
||||
public final function Avarice_OnMessage_Slot OnMessage( |
||||
AcediaObject receiver, |
||||
Text service) |
||||
{ |
||||
return Avarice_OnMessage_Slot(GetServiceSignal(service).NewSlot(receiver)); |
||||
} |
||||
|
||||
private final function Avarice_OnMessage_Signal GetServiceSignal(Text service) |
||||
{ |
||||
local Avarice_OnMessage_Signal result; |
||||
if (service != none) { |
||||
service = service.Copy(); |
||||
} |
||||
else { |
||||
service = Text(_.memory.Allocate(class'Text')); |
||||
} |
||||
result = Avarice_OnMessage_Signal(serviceSignalMap.GetItem(service)); |
||||
if (result == none) |
||||
{ |
||||
result = Avarice_OnMessage_Signal( |
||||
_.memory.Allocate(class'Avarice_OnMessage_Signal')); |
||||
serviceSignalMap.SetItem(service, result); |
||||
} |
||||
else { |
||||
service.FreeSelf(); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Starts caller `AvariceLink`, making it attempt to connect to the Avarice |
||||
* with parameters that should be first specified by the `Initialize()` call. |
||||
* |
||||
* Does nothing if the caller `AvariceLink` is either not initialized or |
||||
* is already active (`IsActive() == true`). |
||||
*/ |
||||
public final function StartUp() |
||||
{ |
||||
local AvariceTcpStream newStream; |
||||
if (tcpStream == none) return; |
||||
if (tcpStream.Get() != none) return; |
||||
|
||||
newStream = AvariceTcpStream(_.memory.Allocate(class'AvariceTcpStream')); |
||||
if (newStream == none) |
||||
{ |
||||
// `linkName` has to be defined if `tcpStream` is defined |
||||
_.logger.Auto(fatalCannotSpawn).Arg(linkName.Copy()); |
||||
return; |
||||
} |
||||
tcpStream.Set(newStream); |
||||
newStream.StartUp(self, class'Avarice'.static.GetReconnectTime()); |
||||
} |
||||
|
||||
/** |
||||
* Shuts down any connections related to the caller `AvariceLink`. |
||||
* |
||||
* Does nothing if the caller `AvariceLink` is either not initialized or |
||||
* is already inactive (`IsActive() == false`). |
||||
*/ |
||||
public final function ShutDown() |
||||
{ |
||||
local Actor storedStream; |
||||
if (tcpStream == none) return; |
||||
storedStream = tcpStream.Get(); |
||||
if (storedStream == none) return; |
||||
|
||||
storedStream.Destroy(); |
||||
tcpStream.Set(none); |
||||
} |
||||
|
||||
/** |
||||
* Checks whether caller `AvariceLink` is currently active: either connected or |
||||
* currently attempts to connect to Avarice. |
||||
* |
||||
* See also `IsConnected()`. |
||||
* |
||||
* @return `true` if caller `AvariceLink` is either connected or currently |
||||
* attempting to connect to Avarice. `false` otherwise. |
||||
*/ |
||||
public final function bool IsActive() |
||||
{ |
||||
if (tcpStream == none) { |
||||
return false; |
||||
} |
||||
return tcpStream.Get() != none; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether caller `AvariceLink` is currently connected or to Avarice. |
||||
* |
||||
* See also `IsActive()`. |
||||
* |
||||
* @return `true` iff caller `AvariceLink` is currently connected to Avarice. |
||||
*/ |
||||
public final function bool IsConnected() |
||||
{ |
||||
local AvariceTcpStream storedStream; |
||||
if (tcpStream == none) { |
||||
return false; |
||||
} |
||||
storedStream = AvariceTcpStream(tcpStream.Get()); |
||||
return storedStream.linkState == STATE_Connected; |
||||
} |
||||
|
||||
/** |
||||
* Returns name caller `AvariceLink` was initialized with. |
||||
* Defined through the config files. |
||||
* |
||||
* @return Name of the caller `AvariceLink`. |
||||
* `none` iff caller link was not yet initialized. |
||||
*/ |
||||
public final function Text GetName() |
||||
{ |
||||
if (linkName != none) { |
||||
return linkName.Copy(); |
||||
} |
||||
// `linkName` cannot be `none` after `Initialize()` call |
||||
return none; |
||||
} |
||||
|
||||
/** |
||||
* Returns host name (without port number) caller `AvariceLink` was |
||||
* initialized with. Defined through the config files. |
||||
* |
||||
* See `GetPort()` method for port number. |
||||
* |
||||
* @return Host name of the caller `AvariceLink`. |
||||
* `none` iff caller link was not yet initialized. |
||||
*/ |
||||
public final function Text GetHost() |
||||
{ |
||||
if (linkHost != none) { |
||||
return linkHost.Copy(); |
||||
} |
||||
// `linkName` cannot be `none` after `Initialize()` call |
||||
return none; |
||||
} |
||||
|
||||
/** |
||||
* Returns port number caller `AvariceLink` was initialized with. |
||||
* Defined through the config files. |
||||
* |
||||
* @return Host name of the caller `AvariceLink`. |
||||
* If caller link was not yet initialized, method makes no guarantees |
||||
* about returned number. |
||||
*/ |
||||
public final function int GetPort() |
||||
{ |
||||
return linkPort; |
||||
} |
||||
|
||||
/** |
||||
* Send a message to the Avarice that caller `AvariceLink` is connected to. |
||||
* |
||||
* Message can only be set if caller `AvariceLink` was initialized and is |
||||
* currently connected (see `IsConnected()`) to Avarice. |
||||
* |
||||
* @param service Name of the service this message is addressed. |
||||
* As an example, to address a database one would specify its name, |
||||
* like "db". Cannot be `none`. |
||||
* @param type Name of this message. As an example, to address |
||||
* a database, one would specify here WHAT that database must do, |
||||
* like "get" to fetch some data. Cannot be `none`. |
||||
* @param parameters Parameters of the command. Can be any value that is |
||||
* JSON-compatible (see `JSONAPI.IsCompatible()` for details). |
||||
* @return `true` if message was successfully sent and `false` otherwise. |
||||
* Note that this method returning `true` does not necessarily mean that |
||||
* message has arrived (which is impossible to know at this moment), |
||||
* instead simply saying that network call to send data was successful. |
||||
* Avarice does not provide any mechanism to verify message arrival, so if |
||||
* you need that confirmation - it is necessary that service you are |
||||
* addressing make a reply. |
||||
*/ |
||||
public final function bool SendMessage( |
||||
Text service, |
||||
Text type, |
||||
AcediaObject parameters) |
||||
{ |
||||
local Mutabletext parametesAsJSON; |
||||
local MutableText message; |
||||
local AvariceTcpStream storedStream; |
||||
if (tcpStream == none) return false; |
||||
if (service == none) return false; |
||||
if (type == none) return false; |
||||
storedStream = AvariceTcpStream(tcpStream.Get()); |
||||
if (storedStream == none) return false; |
||||
if (storedStream.linkState != STATE_Connected) return false; |
||||
parametesAsJSON = _.json.Print(parameters); |
||||
if (parametesAsJSON == none) return false; |
||||
|
||||
message = _.text.Empty(); |
||||
message.Append(T(TSERVICE_PREFIX)) |
||||
.Append(_.json.Print(service)) |
||||
.Append(T(TTYPE_PREFIX)) |
||||
.Append(_.json.Print(type)) |
||||
.Append(T(TPARAMS_PREFIX)) |
||||
.Append(parametesAsJSON) |
||||
.Append(T(TMESSAGE_SUFFIX)); |
||||
storedStream.SendMessage(message); |
||||
message.FreeSelf(); |
||||
parametesAsJSON.FreeSelf(); |
||||
return true; |
||||
} |
||||
|
||||
// This is a public method, but it is not a part of |
||||
// `AvariceLink` interface. |
||||
// It is used as a communication channel with `AvariceTcpStream` and |
||||
// should not be called outside of that class. |
||||
public final function ReceiveNetworkMessage( |
||||
AvariceNetworkMessage message, |
||||
optional AvariceMessage avariceMessage) |
||||
{ |
||||
if (message == ANM_Connected) { |
||||
onConnectedSignal.Emit(); |
||||
} |
||||
else if (message == ANM_Disconnected) { |
||||
onDisconnectedSignal.Emit(); |
||||
} |
||||
else if (message == ANM_Message && avariceMessage != none) { |
||||
GetServiceSignal(avariceMessage.service).Emit(self, avariceMessage); |
||||
} |
||||
else if (message == ANM_Death) { |
||||
onDeathSignal.Emit(); |
||||
tcpStream.Set(none); |
||||
} |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
TSERVICE_PREFIX = 0 |
||||
stringConstants(0) = "&{\"s\":" |
||||
TTYPE_PREFIX = 1 |
||||
stringConstants(1) = ",\"t\":" |
||||
TPARAMS_PREFIX = 2 |
||||
stringConstants(2) = ",\"p\":" |
||||
TMESSAGE_SUFFIX = 3 |
||||
stringConstants(3) = "&}" |
||||
fatalCannotSpawn = (l=LOG_Error,m="Cannot spawn new actor of class `AvariceTcpStream`, avarice link \"%1\" will not be created") |
||||
} |
@ -1,170 +0,0 @@
|
||||
class AvariceTcpLink extends TcpLink |
||||
dependson(LoggerAPI); |
||||
|
||||
var private Global _; |
||||
|
||||
var private string linkName; |
||||
var private string linkHost; |
||||
var private int linkPort; |
||||
var private IpAddr remoteAddress; |
||||
var private int ttt; |
||||
|
||||
var private bool didWorkLastTick; |
||||
|
||||
var private array<byte> buffer; |
||||
|
||||
var private Utf8Encoder encoder; |
||||
var private Utf8Decoder decoder; |
||||
|
||||
var private LoggerAPI.Definition infoSuccess; |
||||
var private LoggerAPI.Definition fatalBadPort; |
||||
var private LoggerAPI.Definition fatalCannotBindPort; |
||||
var private LoggerAPI.Definition fatalCannotResolveHost; |
||||
var private LoggerAPI.Definition fatalCannotConnect; |
||||
|
||||
public final function bool Connect(string name, string host, int port) |
||||
{ |
||||
local InternetLink.IpAddr ip; |
||||
local int usedPort; |
||||
// Apparently `TcpLink` ignores default values for these variables, |
||||
// so we set them here |
||||
linkMode = MODE_Binary; |
||||
receiveMode = RMODE_Manual; |
||||
_ = class'Global'.static.GetInstance(); |
||||
encoder = Utf8Encoder(_.memory.Allocate(class'Utf8Encoder')); |
||||
decoder = Utf8Decoder(_.memory.Allocate(class'Utf8Decoder')); |
||||
linkName = name; |
||||
linkHost = host; |
||||
linkPort = port; |
||||
if (port <= 0) |
||||
{ |
||||
_.logger.Auto(fatalBadPort) |
||||
.ArgInt(port) |
||||
.Arg(_.text.FromString(linkName)); |
||||
return false; |
||||
} |
||||
if (BindPort(, true) <= 0) |
||||
{ |
||||
_.logger.Auto(fatalCannotBindPort) |
||||
.ArgInt(port) |
||||
.Arg(_.text.FromString(name)); |
||||
return false; |
||||
} |
||||
StringToIpAddr(host, remoteAddress); |
||||
remoteAddress.port = port; |
||||
if (remoteAddress.addr == 0) { |
||||
Resolve(host); |
||||
} |
||||
else { |
||||
OpenAddress(); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
event Resolved(IpAddr resolvedAddress) |
||||
{ |
||||
remoteAddress.addr = resolvedAddress.addr; |
||||
OpenAddress(); |
||||
} |
||||
|
||||
private final function bool OpenAddress() |
||||
{ |
||||
if (!OpenNoSteam(remoteAddress)) { |
||||
_.logger.Auto(fatalCannotConnect).Arg(_.text.FromString(linkName)); |
||||
} |
||||
_.logger.Auto(infoSuccess).Arg(_.text.FromString(linkName)); |
||||
} |
||||
|
||||
event ResolveFailed() |
||||
{ |
||||
_.logger.Auto(fatalCannotResolveHost).Arg(_.text.FromString(linkHost)); |
||||
// !Shut down! |
||||
} |
||||
|
||||
event Tick(float delta) |
||||
{ |
||||
local array<byte> toSend; |
||||
local AvariceMessage nextAMessage; |
||||
local MutableText nextMessage; |
||||
local int i, j, dataRead, totalRead, iter; |
||||
local byte data[255]; |
||||
if (didWorkLastTick) |
||||
{ |
||||
didWorkLastTick = false; |
||||
return; |
||||
} |
||||
if (!IsDataPending()) { |
||||
return; |
||||
} |
||||
while (true) { |
||||
dataRead = ReadBinary(255, data); |
||||
for (i = 0; i < dataRead; i += 1) { |
||||
ttt += 1; |
||||
decoder.PushByte(data[i]); |
||||
} |
||||
if (dataRead <= 0) { |
||||
break; |
||||
} |
||||
} |
||||
if (ttt >= 4095) { |
||||
toSend = encoder.Encode(_.text.FromString("FLUSH")); |
||||
data[0] = toSend[0]; |
||||
data[1] = toSend[1]; |
||||
data[2] = toSend[2]; |
||||
data[3] = toSend[3]; |
||||
data[4] = toSend[4]; |
||||
data[5] = 0; |
||||
SendBinary(6, data); |
||||
} |
||||
if (dataRead > 0) { |
||||
didWorkLastTick = true; |
||||
} |
||||
// Obtain! |
||||
nextMessage = decoder.PopText(); |
||||
while (nextMessage != none) |
||||
{ |
||||
Log("SIZE:" @ nextMessage.GetLength() @ ttt); |
||||
StopWatch(false); |
||||
nextAMessage = _.avarice.MessageFromText(nextMessage); |
||||
nextMessage.FreeSelf(); |
||||
nextMessage = nextAMessage.ToText(); |
||||
toSend = encoder.Encode(nextMessage); |
||||
toSend[toSend.length] = 0; |
||||
j = 0; |
||||
for (i = 0; i < toSend.length; i += 1) |
||||
{ |
||||
data[j] = toSend[i]; |
||||
j += 1; |
||||
if (j >= 255) { |
||||
j = 0; |
||||
SendBinary(255, data); |
||||
} |
||||
} |
||||
if (j > 0) { |
||||
SendBinary(j, data); |
||||
} |
||||
nextMessage.FreeSelf(); |
||||
nextMessage = decoder.PopText(); |
||||
StopWatch(true); |
||||
} |
||||
} |
||||
|
||||
event Opened() |
||||
{ |
||||
//Log("[TestTcp] Accepted!"); |
||||
LOG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); |
||||
} |
||||
|
||||
event Closed() |
||||
{ |
||||
//Log("[TestTcp] Closed!"); |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
infoSuccess = (l=LOG_Info,m="Successfully started Avarice link \"%1\"") |
||||
fatalBadPort = (l=LOG_Fatal,m="Bad port \"%1\" specified for Avarice link \"%2\"") |
||||
fatalCannotBindPort = (l=LOG_Fatal,m="Cannot bind port for Avarice link \"%1\"") |
||||
fatalCannotResolveHost = (l=LOG_Fatal,m="Cannot resolve host \"%1\" for Avarice link \"%2\"") |
||||
fatalCannotConnect = (l=LOG_Fatal,m="Connection for Avarice link \"%1\" was rejected") |
||||
} |
Binary file not shown.
@ -0,0 +1,38 @@
|
||||
/** |
||||
* Signal class implementation for `Avarice`'s `OnMessage` signal. |
||||
* Copyright 2021 Anton Tarasenko |
||||
*------------------------------------------------------------------------------ |
||||
* This file is part of Acedia. |
||||
* |
||||
* Acedia is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* Acedia is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class Avarice_OnMessage_Signal extends Signal; |
||||
|
||||
public final function Emit(AvariceLink link, AvariceMessage message) |
||||
{ |
||||
local Slot nextSlot; |
||||
StartIterating(); |
||||
nextSlot = GetNextSlot(); |
||||
while (nextSlot != none) |
||||
{ |
||||
Avarice_OnMessage_Slot(nextSlot).connect(link, message); |
||||
nextSlot = GetNextSlot(); |
||||
} |
||||
CleanEmptySlots(); |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
relatedSlotClass = class'Avarice_OnMessage_Slot' |
||||
} |
@ -0,0 +1,40 @@
|
||||
/** |
||||
* Slot class implementation for `Avarice`'s `OnMessage` signal. |
||||
* Copyright 2021 Anton Tarasenko |
||||
*------------------------------------------------------------------------------ |
||||
* This file is part of Acedia. |
||||
* |
||||
* Acedia is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* Acedia is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with Acedia. If not, see <https://www.gnu.org/licenses/>. |
||||
*/ |
||||
class Avarice_OnMessage_Slot extends Slot; |
||||
|
||||
delegate connect(AvariceLink link, AvariceMessage message) |
||||
{ |
||||
DummyCall(); |
||||
} |
||||
|
||||
protected function Constructor() |
||||
{ |
||||
connect = none; |
||||
} |
||||
|
||||
protected function Finalizer() |
||||
{ |
||||
super.Finalizer(); |
||||
connect = none; |
||||
} |
||||
|
||||
defaultproperties |
||||
{ |
||||
} |
Loading…
Reference in new issue