Aktuellen Stand von SMSPLASH01 wieder hergeholt (separate LS100PortProxy Version für BSMD-AIS, da hier manuell <CR>'s in den Datenstrom eingebaut werden müssen)
This commit is contained in:
parent
09f8a9953f
commit
e672bb8dee
BIN
AIS/LS100PortProxy/Anleitung.docx
Normal file
BIN
AIS/LS100PortProxy/Anleitung.docx
Normal file
Binary file not shown.
79
AIS/LS100PortProxy/LS100PortProxy.csproj
Normal file
79
AIS/LS100PortProxy/LS100PortProxy.csproj
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{1B23254E-62EA-4AAF-803C-AAA0622B4570}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>LS100PortProxy</RootNamespace>
|
||||||
|
<AssemblyName>LS100PortProxy</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||||
|
<TargetFrameworkProfile>
|
||||||
|
</TargetFrameworkProfile>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="MultiplexManager.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="app.config">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</None>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
BIN
AIS/LS100PortProxy/LS100PortProxy.pdf
Normal file
BIN
AIS/LS100PortProxy/LS100PortProxy.pdf
Normal file
Binary file not shown.
35
AIS/LS100PortProxy/LS100PortProxy.sln
Normal file
35
AIS/LS100PortProxy/LS100PortProxy.sln
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.27428.2015
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LS100PortProxy", "LS100PortProxy.csproj", "{1B23254E-62EA-4AAF-803C-AAA0622B4570}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{1B23254E-62EA-4AAF-803C-AAA0622B4570}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1B23254E-62EA-4AAF-803C-AAA0622B4570}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1B23254E-62EA-4AAF-803C-AAA0622B4570}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{1B23254E-62EA-4AAF-803C-AAA0622B4570}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{1B23254E-62EA-4AAF-803C-AAA0622B4570}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1B23254E-62EA-4AAF-803C-AAA0622B4570}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1B23254E-62EA-4AAF-803C-AAA0622B4570}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{1B23254E-62EA-4AAF-803C-AAA0622B4570}.Release|x86.Build.0 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {5F49C6E1-0B93-4637-83E3-685F3DF259C5}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SubversionScc) = preSolution
|
||||||
|
Svn-Managed = True
|
||||||
|
Manager = AnkhSVN - Subversion Support for Visual Studio
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
305
AIS/LS100PortProxy/MultiplexManager.cs
Normal file
305
AIS/LS100PortProxy/MultiplexManager.cs
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
//
|
||||||
|
// Class: MultiplexManager
|
||||||
|
// Current CLR: 4.0.30319.296
|
||||||
|
// System: Microsoft Visual Studio 10.0
|
||||||
|
// Author: dani
|
||||||
|
// Created: 4/8/2013 9:02:48 PM
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013 Informatikbüro Daniel Schick. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
|
namespace LS100PortProxy
|
||||||
|
{
|
||||||
|
public class MultiplexManager
|
||||||
|
{
|
||||||
|
private int ifIdx;
|
||||||
|
private int clientPort;
|
||||||
|
private int serverPort;
|
||||||
|
private string remoteServerAddress;
|
||||||
|
private bool shouldStop = false;
|
||||||
|
private Thread _acceptThread;
|
||||||
|
private Socket _serverSocket;
|
||||||
|
private List<ConnectionInfo> _connections = new List<ConnectionInfo>();
|
||||||
|
private TcpClient client;
|
||||||
|
private Thread _clientThread;
|
||||||
|
private NetworkStream clientStream;
|
||||||
|
private DateTime lastDataReceivedAt;
|
||||||
|
private ILog _log = LogManager.GetLogger(typeof(MultiplexManager));
|
||||||
|
|
||||||
|
private class Chunk
|
||||||
|
{
|
||||||
|
public int length;
|
||||||
|
public byte[] data;
|
||||||
|
public Chunk DeepClone()
|
||||||
|
{
|
||||||
|
Chunk newChunk = new Chunk();
|
||||||
|
newChunk.length = this.length;
|
||||||
|
newChunk.data = new byte[this.length];
|
||||||
|
Array.Copy(this.data, newChunk.data, this.length);
|
||||||
|
return newChunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConnectionInfo
|
||||||
|
{
|
||||||
|
public Socket Socket;
|
||||||
|
public Thread Thread;
|
||||||
|
public Queue<Chunk> chunks = new Queue<Chunk>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiplexManager(int ifIdx, string address, int cPort, int sPort)
|
||||||
|
{
|
||||||
|
this.ifIdx = ifIdx;
|
||||||
|
this.remoteServerAddress = address;
|
||||||
|
this.clientPort = cPort;
|
||||||
|
this.serverPort = sPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartServer()
|
||||||
|
{
|
||||||
|
this.SetupServerSocket();
|
||||||
|
_acceptThread = new Thread(AcceptConnections);
|
||||||
|
_acceptThread.IsBackground = true;
|
||||||
|
_acceptThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopServer()
|
||||||
|
{
|
||||||
|
this.shouldStop = true;
|
||||||
|
_serverSocket.Close();
|
||||||
|
_acceptThread.Join();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ListIfs()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
IPHostEntry localMachineInfo = Dns.GetHostEntry(Dns.GetHostName());
|
||||||
|
for(int i= 0;i< localMachineInfo.AddressList.Length; i++)
|
||||||
|
{
|
||||||
|
IPAddress address = localMachineInfo.AddressList[i];
|
||||||
|
sb.AppendLine(string.Format("# {0}: {1}", i, address.ToString()));
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupServerSocket()
|
||||||
|
{
|
||||||
|
// Resolving local machine information
|
||||||
|
IPHostEntry localMachineInfo = Dns.GetHostEntry(Dns.GetHostName());
|
||||||
|
IPEndPoint myEndpoint = new IPEndPoint(IPAddress.Any, serverPort);
|
||||||
|
//IPEndPoint myEndpoint = new IPEndPoint(localMachineInfo.AddressList[this.ifIdx], serverPort);
|
||||||
|
|
||||||
|
_log.InfoFormat("listening on {0}, port {1}", myEndpoint.Address, serverPort);
|
||||||
|
// Create the socket, bind it, and start listening
|
||||||
|
_serverSocket = new Socket(myEndpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
_serverSocket.Blocking = true;
|
||||||
|
_serverSocket.Bind(myEndpoint);
|
||||||
|
_serverSocket.Listen(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AcceptConnections()
|
||||||
|
{
|
||||||
|
while (!shouldStop)
|
||||||
|
{ // Accept a connection
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Socket socket = _serverSocket.Accept();
|
||||||
|
_log.InfoFormat("new connection from {0}", socket.RemoteEndPoint.ToString());
|
||||||
|
ConnectionInfo connection = new ConnectionInfo();
|
||||||
|
connection.Socket = socket; // Create the thread for the receives.
|
||||||
|
connection.Thread = new Thread(ProcessConnection);
|
||||||
|
connection.Thread.IsBackground = true;
|
||||||
|
connection.Thread.Start(connection);
|
||||||
|
// Store the socket
|
||||||
|
lock (_connections)
|
||||||
|
_connections.Add(connection);
|
||||||
|
}
|
||||||
|
catch (SocketException) { /* tu was */ }
|
||||||
|
Thread.Sleep(250);
|
||||||
|
}
|
||||||
|
this._serverSocket.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessConnection(object state)
|
||||||
|
{
|
||||||
|
ConnectionInfo connection = (ConnectionInfo)state;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (!shouldStop)
|
||||||
|
{
|
||||||
|
// write all chunks in incoming chunk queue to this socket
|
||||||
|
|
||||||
|
if (connection.Socket.Poll(1000, SelectMode.SelectWrite))
|
||||||
|
{
|
||||||
|
while (connection.chunks.Count > 0)
|
||||||
|
{
|
||||||
|
Chunk aChunk = null;
|
||||||
|
lock (_connections)
|
||||||
|
{
|
||||||
|
aChunk = connection.chunks.Dequeue();
|
||||||
|
}
|
||||||
|
int bytesToSend = aChunk.length;
|
||||||
|
byte[] buffer = aChunk.data;
|
||||||
|
while (bytesToSend > 0)
|
||||||
|
{
|
||||||
|
//string testOutput = Encoding.ASCII.GetString(aChunk.data);
|
||||||
|
//string[] lines = testOutput.Split('\r');
|
||||||
|
//foreach(string line in lines)
|
||||||
|
// _log.Debug(line);
|
||||||
|
int actuallySentBytes = connection.Socket.Send(aChunk.data, aChunk.length, SocketFlags.None);
|
||||||
|
bytesToSend -= actuallySentBytes;
|
||||||
|
if (bytesToSend > 0)
|
||||||
|
{
|
||||||
|
byte[] newBuffer = new byte[bytesToSend];
|
||||||
|
Array.Copy(buffer, aChunk.length - bytesToSend, newBuffer, 0, bytesToSend);
|
||||||
|
buffer = newBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aChunk = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// dump queue in this case, packets cannot be sent..
|
||||||
|
lock (_connections)
|
||||||
|
{
|
||||||
|
connection.chunks.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SocketException exc)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Socket exception: " + exc.SocketErrorCode);
|
||||||
|
_log.WarnFormat("SocketException: {0}", exc.SocketErrorCode);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{ Console.WriteLine("Exception: " + exc); }
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_log.InfoFormat("removing connection to {0}", connection.Socket.RemoteEndPoint);
|
||||||
|
connection.Socket.Close();
|
||||||
|
lock (_connections)
|
||||||
|
_connections.Remove(connection);
|
||||||
|
GC.Collect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal void StartClient()
|
||||||
|
{
|
||||||
|
this._clientThread = new Thread(new ThreadStart(this.ClientConnection));
|
||||||
|
this._clientThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConnectClient()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ((this.client != null) && (this.client.Connected)) return;
|
||||||
|
if (this.client != null)
|
||||||
|
{
|
||||||
|
this.client.Close();
|
||||||
|
GC.Collect();
|
||||||
|
}
|
||||||
|
this.client = new TcpClient(this.remoteServerAddress, this.clientPort);
|
||||||
|
this.clientStream = client.GetStream();
|
||||||
|
_log.InfoFormat("TCP stream connected ({0}:{1})", this.remoteServerAddress, this.clientPort);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.ErrorFormat("ConnectClient(): {0}", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClientConnection()
|
||||||
|
{
|
||||||
|
while (!this.shouldStop)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ((this.client == null) || !this.client.Connected) this.ConnectClient();
|
||||||
|
if ((this.client != null) && this.client.Connected && this.clientStream.CanRead)
|
||||||
|
{
|
||||||
|
while (this.clientStream.CanRead && !this.shouldStop)
|
||||||
|
{
|
||||||
|
Chunk chunk = new Chunk();
|
||||||
|
chunk.data = new byte[1024];
|
||||||
|
chunk.length = this.clientStream.Read(chunk.data, 0, 1024);
|
||||||
|
|
||||||
|
byte[] target = new byte[2048]; // einfach größer
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; i < chunk.length; i++, j++)
|
||||||
|
{
|
||||||
|
target[j] = chunk.data[i];
|
||||||
|
if (chunk.data[i] == 10) // LF
|
||||||
|
{
|
||||||
|
target[j] = 13; // CR
|
||||||
|
j++;
|
||||||
|
target[j] = 10; //LF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(j > chunk.length) // es wurden CR eingefügt
|
||||||
|
{
|
||||||
|
chunk.data = target;
|
||||||
|
chunk.length = j;
|
||||||
|
_log.DebugFormat("Chunk replaced, new length {0}", j);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunk.length > 0 && (this._connections.Count > 0))
|
||||||
|
{
|
||||||
|
this.lastDataReceivedAt = DateTime.Now; // reset data timeout
|
||||||
|
|
||||||
|
// clone chunk for each connected client
|
||||||
|
lock (this._connections)
|
||||||
|
{
|
||||||
|
foreach (ConnectionInfo connectionInfo in _connections)
|
||||||
|
{
|
||||||
|
connectionInfo.chunks.Enqueue(chunk.DeepClone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((DateTime.Now - lastDataReceivedAt) > TimeSpan.FromMinutes(10))
|
||||||
|
{
|
||||||
|
// close client connection if no data is received for 10 minutes
|
||||||
|
_log.Info("Server inactive for 10 minutes, disconnecting");
|
||||||
|
if(this.client != null)
|
||||||
|
this.client.Close();
|
||||||
|
this.client = null;
|
||||||
|
}
|
||||||
|
Thread.Sleep(120000); // try connect again in 2 minutes
|
||||||
|
}
|
||||||
|
Thread.Sleep(50);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.ErrorFormat("client-side exception: {0}", ex.Message);
|
||||||
|
if (this.client != null)
|
||||||
|
{
|
||||||
|
this.client.Close();
|
||||||
|
this.client = null;
|
||||||
|
}
|
||||||
|
Thread.Sleep(60000); // 60 Sekunden warten und neu verbinden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(this.client != null)
|
||||||
|
this.client.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
AIS/LS100PortProxy/Program.cs
Normal file
52
AIS/LS100PortProxy/Program.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
|
namespace LS100PortProxy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// http://msdn.microsoft.com/en-GB/library/bbx2eya8.aspx
|
||||||
|
/// Async server socket msdn
|
||||||
|
/// http://msdn.microsoft.com/en-us/library/5w7b7x5f.aspx
|
||||||
|
/// </summary>
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
log4net.Config.XmlConfigurator.Configure();
|
||||||
|
ILog _log = LogManager.GetLogger("Main");
|
||||||
|
_log.Info("PortProxy started");
|
||||||
|
if ((args.Length != 4) && (args.Length != 0))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Usage: <progname> <interface #> <remoteaddress> <clientport> <serverport>");
|
||||||
|
Console.WriteLine("<progname> -> outputs interfaces");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine(MultiplexManager.ListIfs());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ifIdx = Convert.ToInt32(args[0]);
|
||||||
|
string address = args[1];
|
||||||
|
int clientPort = Convert.ToInt32(args[2]);
|
||||||
|
int serverPort = Convert.ToInt32(args[3]);
|
||||||
|
|
||||||
|
MultiplexManager manager = new MultiplexManager(ifIdx, address, clientPort, serverPort);
|
||||||
|
manager.StartServer();
|
||||||
|
|
||||||
|
manager.StartClient();
|
||||||
|
|
||||||
|
Console.WriteLine("Port proxy läuft. Beliebige Taste drücken um zu beenden...");
|
||||||
|
Console.ReadKey();
|
||||||
|
Console.WriteLine("stopping..");
|
||||||
|
manager.StopServer();
|
||||||
|
Console.WriteLine("stopped.");
|
||||||
|
_log.Info("PortProxy stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
AIS/LS100PortProxy/Properties/AssemblyInfo.cs
Normal file
36
AIS/LS100PortProxy/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("LS100PortProxy")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("LS100PortProxy")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2013")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("7ae7a332-a440-42d5-8d33-261e75424fe2")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
32
AIS/LS100PortProxy/app.config
Normal file
32
AIS/LS100PortProxy/app.config
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<configSections>
|
||||||
|
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
|
||||||
|
</configSections>
|
||||||
|
<log4net>
|
||||||
|
<root>
|
||||||
|
<level value="INFO"/>
|
||||||
|
<appender-ref ref="LogFileAppender"/>
|
||||||
|
<appender-ref ref="TraceAppender"/>
|
||||||
|
</root>
|
||||||
|
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
|
||||||
|
<param name="File" value="LS100PortProxy.log"/>
|
||||||
|
<param name="AppendToFile" value="true"/>
|
||||||
|
<rollingStyle value="Size"/>
|
||||||
|
<maxSizeRollBackups value="10"/>
|
||||||
|
<maximumFileSize value="10MB"/>
|
||||||
|
<staticLogFileName value="true"/>
|
||||||
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
|
<param name="ConversionPattern" value="%date [%thread] %-5level [%logger] - %message%newline"/>
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
<appender name="TraceAppender" type="log4net.Appender.TraceAppender">
|
||||||
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
|
<conversionPattern value="%d [%t] %-5p %c %m%n"/>
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
</log4net>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
4
AIS/LS100PortProxy/packages.config
Normal file
4
AIS/LS100PortProxy/packages.config
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="log4net" version="2.0.8" targetFramework="net461" />
|
||||||
|
</packages>
|
||||||
@ -2,6 +2,7 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
@ -27,6 +28,8 @@ namespace bsmd.AISService.AIS
|
|||||||
private int commStateSelectedFlag;
|
private int commStateSelectedFlag;
|
||||||
private int commState;
|
private int commState;
|
||||||
|
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(AIS_ClassB));
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
@ -42,14 +45,10 @@ namespace bsmd.AISService.AIS
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return string.Format("{0}-{1}-{2} {3}:{4}:{5}",
|
return this.timestamp.ToString("yyyy-MM-ddTHH:mm:ss.000Z");
|
||||||
this.timestamp.Year, this.timestamp.Month, this.timestamp.Day,
|
|
||||||
this.timestamp.Hour, this.timestamp.Minute, this.timestamp.Second);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public double Cog
|
public double Cog
|
||||||
{
|
{
|
||||||
get { return this.cog / 10.0f; }
|
get { return this.cog / 10.0f; }
|
||||||
@ -141,7 +140,7 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Trace.WriteLine(string.Format("Error decoding AIS class B posreport: {0}", e.Message));
|
_log.WarnFormat("Error decoding AIS class B posreport: {0}", e.Message);
|
||||||
result = Status.PARSE_ERROR;
|
result = Status.PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
@ -35,6 +36,8 @@ namespace bsmd.AISService.AIS
|
|||||||
private int assignedMode;
|
private int assignedMode;
|
||||||
private int spare3;
|
private int spare3;
|
||||||
|
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(AIS_ClassBExt));
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
@ -120,7 +123,7 @@ namespace bsmd.AISService.AIS
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Trace.WriteLine(string.Format("Error decoding AIS class B Ext posreport: {0}", e.Message));
|
_log.WarnFormat("Error decoding AIS class B Ext posreport: {0}", e.Message);
|
||||||
result = Status.PARSE_ERROR;
|
result = Status.PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Diagnostics;
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
@ -17,6 +17,7 @@ namespace bsmd.AISService.AIS
|
|||||||
private string callsign;
|
private string callsign;
|
||||||
private int dimension;
|
private int dimension;
|
||||||
private int spare;
|
private int spare;
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(AIS_ClassBStatic));
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -57,6 +58,10 @@ namespace bsmd.AISService.AIS
|
|||||||
get { return this.shipType; }
|
get { return this.shipType; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Dimension { get { return this.dimension; } }
|
||||||
|
|
||||||
|
public int Spare { get { return this.spare; } }
|
||||||
|
|
||||||
// Todo: Dimensions..
|
// Todo: Dimensions..
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -120,7 +125,7 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Trace.WriteLine(string.Format("Error decoding AIS class B static data: {0}", e.Message));
|
_log.WarnFormat("Error decoding AIS class B static data: {0}", e.Message);
|
||||||
result = Status.PARSE_ERROR;
|
result = Status.PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
@ -23,6 +23,8 @@ namespace bsmd.AISService.AIS
|
|||||||
private int raim;
|
private int raim;
|
||||||
private int commstate;
|
private int commstate;
|
||||||
|
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(AIS_PosReport));
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
|
|
||||||
public Guid Id { get { if (!this.id.HasValue) this.id = Guid.NewGuid(); return this.id.Value; } }
|
public Guid Id { get { if (!this.id.HasValue) this.id = Guid.NewGuid(); return this.id.Value; } }
|
||||||
@ -38,9 +40,7 @@ namespace bsmd.AISService.AIS
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return string.Format("{0}-{1}-{2} {3}:{4}:{5}",
|
return this.timestamp.ToString("yyyy-MM-ddTHH:mm:ss.000Z");
|
||||||
this.timestamp.Year, this.timestamp.Month, this.timestamp.Day,
|
|
||||||
this.timestamp.Hour, this.timestamp.Minute, this.timestamp.Second);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Trace.WriteLine(string.Format("Error decoding AIS pos report: {0}", e.Message));
|
_log.WarnFormat("Error decoding AIS pos report: {0}", e.Message);
|
||||||
result = Status.PARSE_ERROR;
|
result = Status.PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
@ -25,8 +26,9 @@ public class AIS_QueueManager
|
|||||||
private List<SerialDataHandler> serialHandlerList = new List<SerialDataHandler>();
|
private List<SerialDataHandler> serialHandlerList = new List<SerialDataHandler>();
|
||||||
private List<TelnetDataHandler> telnetHandlerList = new List<TelnetDataHandler>();
|
private List<TelnetDataHandler> telnetHandlerList = new List<TelnetDataHandler>();
|
||||||
private List<AIS_Target> dbUpdateQueue = new List<AIS_Target>();
|
private List<AIS_Target> dbUpdateQueue = new List<AIS_Target>();
|
||||||
private Timer dbUpdateTimer = new Timer();
|
private System.Timers.Timer dbUpdateTimer = new System.Timers.Timer();
|
||||||
private bool isStarted = false;
|
private bool isStarted = false;
|
||||||
|
private Mutex dbSingleMutex = new Mutex();
|
||||||
|
|
||||||
#region Construction
|
#region Construction
|
||||||
|
|
||||||
@ -77,6 +79,9 @@ public class AIS_QueueManager
|
|||||||
#region event handler
|
#region event handler
|
||||||
|
|
||||||
void dbUpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
|
void dbUpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (dbSingleMutex.WaitOne(0))
|
||||||
{
|
{
|
||||||
while (this.dbUpdateQueue.Count > 0)
|
while (this.dbUpdateQueue.Count > 0)
|
||||||
{
|
{
|
||||||
@ -94,12 +99,12 @@ public class AIS_QueueManager
|
|||||||
lock (this.activeTargetList)
|
lock (this.activeTargetList)
|
||||||
{
|
{
|
||||||
|
|
||||||
for(int i=0;i<this.activeTargetList.Count; i++)
|
for (int i = 0; i < this.activeTargetList.Count; i++)
|
||||||
{
|
{
|
||||||
if (!this.activeTargetList[i].LastUpdate.HasValue)
|
if (!this.activeTargetList[i].LastUpdate.HasValue)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int diffmin = (int) (DateTime.Now - this.activeTargetList[i].LastUpdate.Value).TotalMinutes;
|
int diffmin = (int)(DateTime.Now - this.activeTargetList[i].LastUpdate.Value).TotalMinutes;
|
||||||
|
|
||||||
if (diffmin > this.configuration.TargetStaleMins)
|
if (diffmin > this.configuration.TargetStaleMins)
|
||||||
{
|
{
|
||||||
@ -108,7 +113,8 @@ public class AIS_QueueManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dbSingleMutex.ReleaseMutex();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decoder_AISMessageReceived(AIS message)
|
void decoder_AISMessageReceived(AIS message)
|
||||||
|
|||||||
@ -3,6 +3,8 @@ using System.Collections;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
public class AIS_StaticData : AIS
|
public class AIS_StaticData : AIS
|
||||||
@ -32,6 +34,8 @@ namespace bsmd.AISService.AIS
|
|||||||
private int dte;
|
private int dte;
|
||||||
private int spare;
|
private int spare;
|
||||||
|
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(AIS_StaticData));
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
@ -120,21 +124,30 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int DBShipType { get { return this.shiptype; } }
|
||||||
|
|
||||||
|
public int DBDimension { get { return this.dimension; } }
|
||||||
|
|
||||||
|
public int DBTypeOfDevice { get { return this.typeofdevice; } }
|
||||||
|
|
||||||
|
public int DTE { get { return this.dte; } }
|
||||||
|
|
||||||
|
public int Spare { get { return this.spare; } }
|
||||||
|
|
||||||
public string DBETA
|
public string DBETA
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (this.eta.HasValue)
|
if (this.eta.HasValue)
|
||||||
{
|
{
|
||||||
return string.Format("{0}-{1}-{2} {3}:{4}:{5}",
|
return this.eta.Value.ToString("yyyy-MM-ddTHH:mm:ss.000Z");
|
||||||
this.eta.Value.Year, this.eta.Value.Month, this.eta.Value.Day,
|
|
||||||
this.eta.Value.Hour, this.eta.Value.Minute, this.eta.Value.Second);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -197,8 +210,8 @@ namespace bsmd.AISService.AIS
|
|||||||
this.eta = new DateTime(DateTime.Now.Year, this.etamonth, this.etaday, this.etahour, this.etaminute, 0);
|
this.eta = new DateTime(DateTime.Now.Year, this.etamonth, this.etaday, this.etahour, this.etaminute, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception) {
|
catch(Exception e) {
|
||||||
Trace.WriteLine("ERROR creating ETA timestamp");
|
_log.WarnFormat("ETA timestamp creation failed: {0}", e.Message);
|
||||||
}
|
}
|
||||||
this.maxpresetstaticdraught = AIS.GetInt(bits, 294, 301);
|
this.maxpresetstaticdraught = AIS.GetInt(bits, 294, 301);
|
||||||
|
|
||||||
@ -219,7 +232,7 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Trace.WriteLine(string.Format("Error decoding AIS static data: {0}", e.Message));
|
_log.WarnFormat("Error decoding AIS static data: {0}", e.Message);
|
||||||
result = Status.PARSE_ERROR;
|
result = Status.PARSE_ERROR;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -13,6 +13,8 @@ using System.IO;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
public class AIS_Telnet
|
public class AIS_Telnet
|
||||||
@ -29,6 +31,8 @@ namespace bsmd.AISService.AIS
|
|||||||
private int port;
|
private int port;
|
||||||
private DateTime? lastRead;
|
private DateTime? lastRead;
|
||||||
|
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(AIS_Telnet));
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public AIS_Telnet(string theHostname, int thePort)
|
public AIS_Telnet(string theHostname, int thePort)
|
||||||
@ -99,7 +103,7 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Trace.WriteLine(string.Format("exception reading from tcp stream: {0}", ex.Message));
|
_log.ErrorFormat("exception reading from tcp stream: {0}", ex.Message);
|
||||||
result = "";
|
result = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +118,7 @@ namespace bsmd.AISService.AIS
|
|||||||
{
|
{
|
||||||
this.tcpSocket.Close();
|
this.tcpSocket.Close();
|
||||||
this.tcpSocket = null;
|
this.tcpSocket = null;
|
||||||
System.Diagnostics.Trace.WriteLine("closing inactive TcpClient");
|
_log.Info("closing inactive TcpClient");
|
||||||
this.lastRead = DateTime.Now; // reset timer
|
this.lastRead = DateTime.Now; // reset timer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,12 +142,11 @@ namespace bsmd.AISService.AIS
|
|||||||
if ((this.tcpSocket != null) && (this.tcpSocket.Connected)) return;
|
if ((this.tcpSocket != null) && (this.tcpSocket.Connected)) return;
|
||||||
this.tcpSocket = new TcpClient(this.hostname, this.port);
|
this.tcpSocket = new TcpClient(this.hostname, this.port);
|
||||||
this.tcpStream = tcpSocket.GetStream();
|
this.tcpStream = tcpSocket.GetStream();
|
||||||
System.Diagnostics.Trace.WriteLine(string.Format("TCP stream connected ({0}:{1})", this.hostname, this.port));
|
_log.InfoFormat("TCP stream connected ({0}:{1})", this.hostname, this.port);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Trace.WriteLine(
|
_log.WarnFormat("AIS_Telnet: cannot connect to ({0}:{1}) : {2}", this.hostname, this.port, ex.Message);
|
||||||
string.Format("AIS_Telnet: cannot connect to ({0}:{1}) : {2}", this.hostname, this.port, ex.Message));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
@ -10,6 +11,8 @@ namespace bsmd.AISService.AIS
|
|||||||
protected string data;
|
protected string data;
|
||||||
protected string[] elements = null;
|
protected string[] elements = null;
|
||||||
|
|
||||||
|
protected static ILog _log = LogManager.GetLogger(typeof(NMEA));
|
||||||
|
|
||||||
public enum Status
|
public enum Status
|
||||||
{
|
{
|
||||||
OK,
|
OK,
|
||||||
@ -60,7 +63,7 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Trace.WriteLine(string.Format("Error decoding sentence: {0}, {1}", ex.Message, ex.StackTrace));
|
_log.ErrorFormat("Error decoding sentence: {0}, {1}", ex.Message, ex.StackTrace);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
@ -75,11 +76,11 @@ namespace bsmd.AISService.AIS
|
|||||||
{
|
{
|
||||||
string fillbits_string = this.elements[6].Substring(0, this.elements[6].IndexOf('*'));
|
string fillbits_string = this.elements[6].Substring(0, this.elements[6].IndexOf('*'));
|
||||||
if(!Int32.TryParse(fillbits_string, out this.fillbits))
|
if(!Int32.TryParse(fillbits_string, out this.fillbits))
|
||||||
System.Diagnostics.Trace.WriteLine("AIS_Sentence.Decode(): fillbits are no integer");
|
_log.Warn("AIS_Sentence.Decode(): fillbits are no integer");
|
||||||
}
|
}
|
||||||
catch (ArgumentOutOfRangeException)
|
catch (ArgumentOutOfRangeException)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Trace.WriteLine("AIS_Sentence.Decode(): split() problem, trouble decoding fillbits");
|
_log.Warn("AIS_Sentence.Decode(): split() problem, trouble decoding fillbits");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,7 +48,7 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
catch (FormatException)
|
catch (FormatException)
|
||||||
{
|
{
|
||||||
Trace.WriteLine("NMEA [PNMLS] input format error");
|
_log.Warn("NMEA [PNMLS] input format error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
@ -10,6 +11,8 @@ namespace bsmd.AISService.AIS
|
|||||||
private Serial_IO serial_IO;
|
private Serial_IO serial_IO;
|
||||||
private AIS_Decoder decoder;
|
private AIS_Decoder decoder;
|
||||||
|
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(SerialDataHandler));
|
||||||
|
|
||||||
public SerialDataHandler(Serial_IO io, AIS_Decoder decoder)
|
public SerialDataHandler(Serial_IO io, AIS_Decoder decoder)
|
||||||
{
|
{
|
||||||
this.serial_IO = io;
|
this.serial_IO = io;
|
||||||
@ -54,7 +57,7 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Trace.WriteLine("Serial data handler: NMEA decoder returned null sentence");
|
_log.Info("Serial data handler: NMEA decoder returned null sentence");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -96,7 +96,6 @@ namespace bsmd.AISService.AIS
|
|||||||
{
|
{
|
||||||
string line = this.port.ReadLine();
|
string line = this.port.ReadLine();
|
||||||
this.OnInputLineRead(line);
|
this.OnInputLineRead(line);
|
||||||
//System.Diagnostics.Trace.WriteLine(line);
|
|
||||||
}
|
}
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,8 @@ using System.Collections.Generic;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.AIS
|
namespace bsmd.AISService.AIS
|
||||||
{
|
{
|
||||||
public class TelnetDataHandler
|
public class TelnetDataHandler
|
||||||
@ -21,6 +23,8 @@ namespace bsmd.AISService.AIS
|
|||||||
Thread readerThread;
|
Thread readerThread;
|
||||||
bool requestStop;
|
bool requestStop;
|
||||||
|
|
||||||
|
internal static ILog _log = LogManager.GetLogger(typeof(TelnetDataHandler));
|
||||||
|
|
||||||
public TelnetDataHandler(AIS_Telnet telnetConnection, AIS_Decoder aisDecoder)
|
public TelnetDataHandler(AIS_Telnet telnetConnection, AIS_Decoder aisDecoder)
|
||||||
{
|
{
|
||||||
this.aisTelnet = telnetConnection;
|
this.aisTelnet = telnetConnection;
|
||||||
@ -70,7 +74,7 @@ namespace bsmd.AISService.AIS
|
|||||||
private void ReaderThread()
|
private void ReaderThread()
|
||||||
{
|
{
|
||||||
NMEA.Status nmea_Status = NMEA.Status.OK;
|
NMEA.Status nmea_Status = NMEA.Status.OK;
|
||||||
System.Diagnostics.Trace.WriteLine("starting telnet reader thread");
|
_log.Info("starting telnet reader thread");
|
||||||
while (!requestStop)
|
while (!requestStop)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -92,7 +96,7 @@ namespace bsmd.AISService.AIS
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Trace.WriteLine("Serial data handler: NMEA decoder returned null/empty sentence");
|
_log.Info("Serial data handler: NMEA decoder returned null/empty sentence");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,8 +105,7 @@ namespace bsmd.AISService.AIS
|
|||||||
var st = new StackTrace(ex, true);
|
var st = new StackTrace(ex, true);
|
||||||
var frame = st.GetFrame(0);
|
var frame = st.GetFrame(0);
|
||||||
var line = frame.GetFileLineNumber();
|
var line = frame.GetFileLineNumber();
|
||||||
Trace.WriteLine(string.Format("Exception in telnet reader thread: {0}, top frame ln {1}", ex.Message, line));
|
_log.WarnFormat("Exception in telnet reader thread: {0}, top frame ln {1}", ex.Message, line);
|
||||||
Trace.WriteLine(ex.StackTrace);
|
|
||||||
}
|
}
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,6 +66,7 @@ namespace bsmd.AISService
|
|||||||
protected override void OnStop()
|
protected override void OnStop()
|
||||||
{
|
{
|
||||||
this.qManager.Stop();
|
this.qManager.Stop();
|
||||||
|
_log.Info("AIS Service stopped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Init(string[] args)
|
protected void Init(string[] args)
|
||||||
@ -74,7 +75,7 @@ namespace bsmd.AISService
|
|||||||
|
|
||||||
if (configuration == null)
|
if (configuration == null)
|
||||||
{
|
{
|
||||||
Console.WriteLine(string.Format("cannot read configuration {0}", config_filename));
|
_log.ErrorFormat("cannot read configuration {0}", config_filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ namespace bsmd.AISService
|
|||||||
dbConnector.ConnectionString = configuration.DBConnectionString;
|
dbConnector.ConnectionString = configuration.DBConnectionString;
|
||||||
if (!dbConnector.Open())
|
if (!dbConnector.Open())
|
||||||
{
|
{
|
||||||
Console.WriteLine("Error connecting to database");
|
_log.Error("Error connecting to database");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,14 +91,15 @@ namespace bsmd.AISService
|
|||||||
|
|
||||||
this.qManager = new AIS_QueueManager(configuration, AISStation.CreateSerial_IOs(stationList), AISStation.CreateAIS_Telnets(stationList));
|
this.qManager = new AIS_QueueManager(configuration, AISStation.CreateSerial_IOs(stationList), AISStation.CreateAIS_Telnets(stationList));
|
||||||
qManager.DBUpdateRequired += new AIS_QueueManager.AISQueueChangedHandler(dbConnector.Update);
|
qManager.DBUpdateRequired += new AIS_QueueManager.AISQueueChangedHandler(dbConnector.Update);
|
||||||
qManager.AISQueueChanged += new AIS_QueueManager.AISQueueChangedHandler(aisDecoder_AISMessageReceived);
|
// qManager.AISQueueChanged += new AIS_QueueManager.AISQueueChangedHandler(aisDecoder_AISMessageReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
protected void aisDecoder_AISMessageReceived(AIS_Target target)
|
protected void aisDecoder_AISMessageReceived(AIS_Target target)
|
||||||
{
|
{
|
||||||
Console.WriteLine(string.Format("{0}: {1} Pos:{2} {3} at {4}", target.Station, target.Name, target.Latitude, target.Longitude, target.LastUpdate));
|
Console.WriteLine(string.Format("{0}: {1} Pos:{2} {3} at {4}", target.Station, target.Name, target.Latitude, target.Longitude, target.LastUpdate));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,31 @@
|
|||||||
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||||
<section name="bsmd.AISService.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
|
<section name="bsmd.AISService.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
|
||||||
</sectionGroup>
|
</sectionGroup>
|
||||||
|
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
|
||||||
</configSections>
|
</configSections>
|
||||||
|
<log4net>
|
||||||
|
<root>
|
||||||
|
<level value="ALL"/>
|
||||||
|
<appender-ref ref="LogFileAppender"/>
|
||||||
|
<appender-ref ref="TraceAppender"/>
|
||||||
|
</root>
|
||||||
|
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
|
||||||
|
<param name="File" value="C:\work\Logs\AISService.log"/>
|
||||||
|
<param name="AppendToFile" value="true"/>
|
||||||
|
<rollingStyle value="Size"/>
|
||||||
|
<maxSizeRollBackups value="10"/>
|
||||||
|
<maximumFileSize value="10MB"/>
|
||||||
|
<staticLogFileName value="true"/>
|
||||||
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
|
<param name="ConversionPattern" value="%date [%thread] %-5level [%logger] - %message%newline"/>
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
<appender name="TraceAppender" type="log4net.Appender.TraceAppender">
|
||||||
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
|
<conversionPattern value="%d [%t] %-5p %c %m%n"/>
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
</log4net>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||||
</startup>
|
</startup>
|
||||||
|
|||||||
@ -8,12 +8,14 @@ using System.Collections.Generic;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
using bsmd.AISService.AIS;
|
using bsmd.AISService.AIS;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.DB
|
namespace bsmd.AISService.DB
|
||||||
{
|
{
|
||||||
|
internal class AISPosReport : AISBaseEntity {
|
||||||
|
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(AISPosReport));
|
||||||
|
|
||||||
internal class AISPosReport : AISBaseEntity
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves a (class A or B) position report
|
/// Saves a (class A or B) position report
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -51,8 +53,8 @@ namespace bsmd.AISService.DB
|
|||||||
AIS_ClassB pr = target.LastPosReport as AIS_ClassB;
|
AIS_ClassB pr = target.LastPosReport as AIS_ClassB;
|
||||||
aisStation.UpdateWithPositionReport(pr.MMSI, pr.Latitude, pr.Longitude, pr.Timestamp);
|
aisStation.UpdateWithPositionReport(pr.MMSI, pr.Latitude, pr.Longitude, pr.Timestamp);
|
||||||
|
|
||||||
string query = string.Format("INSERT INTO aisposreport (Id, MMSI, NavStatus, ROT, COG, SOG, Accuracy, Longitude, Latitude, Heading, Timestamp, Reserved, Spare, Raim, CommState, Stationid) VALUES ('{0}', {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, '{10}', {11},{12},{13},{14},'{15}')",
|
string query = string.Format("INSERT INTO aisposreport (Id, MMSI, NavStatus, ROT, COG, SOG, Accuracy, Longitude, Latitude, Heading, Timestamp, Reserved, Spare, Raim, CommState, AISStationId) VALUES ('{0}', {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, '{10}', {11}, {12}, {13}, {14}, '{15}')",
|
||||||
pr.MMSI, 0, 0, pr.CogVal, pr.SogVal, 0, pr.LongitudeVal, pr.LatitudeVal,
|
pr.Id, pr.MMSI, 0, 0, pr.CogVal, pr.SogVal, 0, pr.LongitudeVal, pr.LatitudeVal,
|
||||||
pr.TrueHeading ?? 511, pr.DBTimestamp, pr.Reserved, pr.Spare, pr.Raim, pr.CommState, (aisStation != null) ? aisStation.Id : Guid.Empty);
|
pr.TrueHeading ?? 511, pr.DBTimestamp, pr.Reserved, pr.Spare, pr.Raim, pr.CommState, (aisStation != null) ? aisStation.Id : Guid.Empty);
|
||||||
|
|
||||||
con.ExecuteNonQuery(query);
|
con.ExecuteNonQuery(query);
|
||||||
@ -62,12 +64,12 @@ namespace bsmd.AISService.DB
|
|||||||
|
|
||||||
if (target.LastPosReport is AIS_ClassBExt)
|
if (target.LastPosReport is AIS_ClassBExt)
|
||||||
{
|
{
|
||||||
Trace.WriteLine("AIS class B ext not supported (yet)");
|
_log.Info("AIS class B ext not supported (yet)");
|
||||||
// TODO: Import ClassB Extended report!
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Trace.WriteLine(string.Format("save pos report: we should not be here.. class type: {0}", target));
|
_log.WarnFormat("save pos report: we should not be here.. class type: {0}", target);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ using System.ComponentModel;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
using bsmd.AISService.AIS;
|
using bsmd.AISService.AIS;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.DB
|
namespace bsmd.AISService.DB
|
||||||
{
|
{
|
||||||
@ -21,6 +22,7 @@ namespace bsmd.AISService.DB
|
|||||||
}
|
}
|
||||||
|
|
||||||
private const string LoadDBShipsQuery = "SELECT aisposreport.MMSI, aisposreport.timestamp, aisposreport.latitude, aisposreport.longitude, aisposreport.stationid, aisposreport.cog, aisposreport.heading, aisposreport.navstatus, aisstaticdata.callsign, aisstaticdata.name, aisstaticdata.shiptype, aisstaticdata.classb, aisstaticdata.shipdescription FROM aisstaticdata JOIN hotposition ON aisstaticdata.mmsi = hotposition.mmsi JOIN aisposreport ON aisposreport.id = hotposition.pid ORDER BY aisstaticdata.name";
|
private const string LoadDBShipsQuery = "SELECT aisposreport.MMSI, aisposreport.timestamp, aisposreport.latitude, aisposreport.longitude, aisposreport.stationid, aisposreport.cog, aisposreport.heading, aisposreport.navstatus, aisstaticdata.callsign, aisstaticdata.name, aisstaticdata.shiptype, aisstaticdata.classb, aisstaticdata.shipdescription FROM aisstaticdata JOIN hotposition ON aisstaticdata.mmsi = hotposition.mmsi JOIN aisposreport ON aisposreport.id = hotposition.pid ORDER BY aisstaticdata.name";
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(AISStaticData));
|
||||||
|
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
@ -188,12 +190,12 @@ namespace bsmd.AISService.DB
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">target to save</param>
|
/// <param name="target">target to save</param>
|
||||||
/// <returns>id of insert operation (to update hotposition table)</returns>
|
/// <returns>id of insert operation (to update hotposition table)</returns>
|
||||||
public static int? Save(AIS_Target target, DBConnector con, AISStation aisStation)
|
public static Guid? Save(AIS_Target target, DBConnector con, AISStation aisStation)
|
||||||
{
|
{
|
||||||
if(target.LastStaticData == null) return null;
|
if(target.LastStaticData == null) return null;
|
||||||
|
|
||||||
int mmsi = -1;
|
int mmsi = -1;
|
||||||
int id = -1;
|
Guid id = Guid.Empty;
|
||||||
|
|
||||||
if(target.LastStaticData is AIS_StaticData) {
|
if(target.LastStaticData is AIS_StaticData) {
|
||||||
mmsi = ((AIS_StaticData)target.LastStaticData).MMSI;
|
mmsi = ((AIS_StaticData)target.LastStaticData).MMSI;
|
||||||
@ -207,7 +209,7 @@ namespace bsmd.AISService.DB
|
|||||||
|
|
||||||
if (result != null) // update
|
if (result != null) // update
|
||||||
{
|
{
|
||||||
id = Convert.ToInt32(result);
|
id = (Guid) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Class A
|
#region Class A
|
||||||
@ -216,87 +218,58 @@ namespace bsmd.AISService.DB
|
|||||||
{
|
{
|
||||||
AIS_StaticData staticData = target.LastStaticData as AIS_StaticData;
|
AIS_StaticData staticData = target.LastStaticData as AIS_StaticData;
|
||||||
|
|
||||||
if (id >= 0)
|
if (id != Guid.Empty)
|
||||||
{
|
{
|
||||||
if (staticData.ETA.HasValue)
|
query = string.Format("UPDATE aisstaticdata SET imonumber={0}, callsign='{1}', name='{2}', shiptype={3}, dimension={4}, typeofdevice={5}, maxpresetstaticdraught={6}, " +
|
||||||
{
|
"destination='{7}', dte={8}, spare={9}, mmsi={10}, eta={11}, classb={12}, breadth={13}, length={14}, aisstation_id='{15}' " +
|
||||||
query = string.Format("UPDATE aisstaticdata SET imonumber={0}, callsign='{1}', name='{2}', shiptype={3}, typeofdevice='{4}', shipdescription='{5}', eta='{6}', destination='{7}', breadth={8}, length={9}, draught='{10}', stationid={11}, classb=0 WHERE id={12}",
|
"WHERE Id='{16}'",
|
||||||
staticData.IMONumber,
|
staticData.IMONumber,
|
||||||
staticData.Callsign.Replace("'","''"),
|
(staticData.Callsign ?? "").Replace("'", "''"),
|
||||||
staticData.Name.Replace("'", "''"),
|
(staticData.Name ?? "").Replace("'", "''"),
|
||||||
staticData.ShipTypeVal,
|
staticData.ShipTypeVal,
|
||||||
staticData.DeviceName,
|
staticData.DBDimension,
|
||||||
staticData.ShipType,
|
staticData.DBTypeOfDevice,
|
||||||
staticData.DBETA,
|
staticData.Draught,
|
||||||
staticData.Destination.Replace("'", "''"),
|
(staticData.Destination ?? "").Replace("'", "''"),
|
||||||
|
staticData.DTE,
|
||||||
|
staticData.Spare,
|
||||||
|
staticData.MMSI,
|
||||||
|
staticData.ETA.HasValue ? string.Format("'{0}'", staticData.DBETA) : "NULL",
|
||||||
|
0,
|
||||||
staticData.Breadth,
|
staticData.Breadth,
|
||||||
staticData.Length,
|
staticData.Length,
|
||||||
staticData.Draught,
|
|
||||||
aisStation.Id,
|
|
||||||
id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
query = string.Format("UPDATE aisstaticdata SET imonumber={0}, callsign='{1}', name='{2}', shiptype={3}, typeofdevice='{4}', shipdescription='{5}', destination='{6}', breadth={7}, length={8}, draught='{9}', stationid={10}, classb=0 WHERE id={11}",
|
|
||||||
staticData.IMONumber,
|
|
||||||
staticData.Callsign.Replace("'", "''"),
|
|
||||||
staticData.Name.Replace("'", "''"),
|
|
||||||
staticData.ShipTypeVal,
|
|
||||||
staticData.DeviceName,
|
|
||||||
staticData.ShipType,
|
|
||||||
staticData.Destination.Replace("'", "''"),
|
|
||||||
staticData.Breadth,
|
|
||||||
staticData.Length,
|
|
||||||
staticData.Draught,
|
|
||||||
aisStation.Id,
|
aisStation.Id,
|
||||||
id);
|
id);
|
||||||
|
|
||||||
}
|
|
||||||
con.ExecuteNonQuery(query);
|
con.ExecuteNonQuery(query);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (staticData.ETA.HasValue)
|
id = Guid.NewGuid();
|
||||||
{
|
|
||||||
|
|
||||||
query = string.Format("INSERT INTO aisstaticdata SET imonumber={0}, callsign='{1}', name='{2}', shiptype={3}, typeofdevice='{4}', shipdescription='{5}', eta='{6}', destination='{7}', breadth={8}, length={9}, draught='{10}', stationid={11}, mmsi={12}, classb=0",
|
query = string.Format("INSERT INTO aisstaticdata (Id, aisversion, imoNumber, callsign, name, shiptype, dimension, typeofdevice, maxpresetstaticdraught, destination, " +
|
||||||
|
"dte, spare, mmsi, eta, classb, breadth, length, aisstation_id) VALUES ('{0}', {1}, {2}, '{3}', '{4}', {5}, {6}, {7}, {8}, '{9}', {10}, {11}, {12}, {13}, {14}, {15}, {16}, '{17}')",
|
||||||
|
id,
|
||||||
|
0,
|
||||||
staticData.IMONumber,
|
staticData.IMONumber,
|
||||||
staticData.Callsign.Replace("'", "''"),
|
(staticData.Callsign ?? "").Replace("'", "''"),
|
||||||
staticData.Name.Replace("'", "''"),
|
(staticData.Name ?? "").Replace("'", "''"),
|
||||||
staticData.ShipTypeVal,
|
staticData.ShipTypeVal,
|
||||||
staticData.DeviceName,
|
staticData.DBDimension,
|
||||||
staticData.ShipType,
|
staticData.DBTypeOfDevice,
|
||||||
staticData.DBETA,
|
staticData.Draught,
|
||||||
staticData.Destination.Replace("'", "''"),
|
(staticData.Destination ?? "").Replace("'", "''"),
|
||||||
|
staticData.DTE,
|
||||||
|
staticData.Spare,
|
||||||
|
staticData.MMSI,
|
||||||
|
staticData.ETA.HasValue ? string.Format("'{0}'", staticData.DBETA) : "NULL",
|
||||||
|
0,
|
||||||
staticData.Breadth,
|
staticData.Breadth,
|
||||||
staticData.Length,
|
staticData.Length,
|
||||||
staticData.Draught,
|
aisStation.Id.Value);
|
||||||
aisStation.Id,
|
|
||||||
staticData.MMSI);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
query = string.Format("INSERT INTO aisstaticdata SET imonumber={0}, callsign='{1}', name='{2}', shiptype={3}, typeofdevice='{4}', shipdescription='{5}', destination='{6}', breadth={7}, length={8}, draught='{9}', stationid={10}, mmsi={11}, classb=0",
|
|
||||||
staticData.IMONumber,
|
|
||||||
staticData.Callsign.Replace("'", "''"),
|
|
||||||
staticData.Name.Replace("'", "''"),
|
|
||||||
staticData.ShipTypeVal,
|
|
||||||
staticData.DeviceName,
|
|
||||||
staticData.ShipType,
|
|
||||||
staticData.Destination.Replace("'", "''"),
|
|
||||||
staticData.Breadth,
|
|
||||||
staticData.Length,
|
|
||||||
staticData.Draught,
|
|
||||||
aisStation.Id,
|
|
||||||
staticData.MMSI);
|
|
||||||
}
|
|
||||||
|
|
||||||
con.ExecuteNonQuery(query);
|
con.ExecuteNonQuery(query);
|
||||||
|
|
||||||
id = Convert.ToInt32(con.ExecuteScalar("SELECT LAST_INSERT_ID()"));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -307,31 +280,32 @@ namespace bsmd.AISService.DB
|
|||||||
{
|
{
|
||||||
AIS_ClassBStatic staticData = target.LastStaticData as AIS_ClassBStatic;
|
AIS_ClassBStatic staticData = target.LastStaticData as AIS_ClassBStatic;
|
||||||
|
|
||||||
if (id >= 0) // Update
|
if (id != Guid.Empty) // Update
|
||||||
{
|
{
|
||||||
query = string.Format("UPDATE aisstaticdata SET stationid={0}, shiptype={1}, classb=1", aisStation.Id, staticData.ShipTypeVal);
|
query = string.Format("UPDATE aisstaticdata SET aisstation_id = '{0}', shiptype={1}, classb=1, dimension = {2}, spare = {3}",
|
||||||
if(staticData.Callsign != null) query += string.Format(", callsign='{0}'", staticData.Callsign);
|
aisStation.Id, staticData.ShipTypeVal, staticData.Dimension, staticData.Spare);
|
||||||
if(staticData.Name != null) query += string.Format(", name='{0}'", staticData.Name);
|
if(staticData.Callsign != null) query += string.Format(", callsign='{0}'", staticData.Callsign.Replace("'", "''"));
|
||||||
if(staticData.VendorId != null) query += string.Format(", typeofdevice='{0}'", staticData.VendorId);
|
if(staticData.Name != null) query += string.Format(", name='{0}'", staticData.Name.Replace("'","''"));
|
||||||
if(staticData.ShipType != null) query += string.Format(", shipdescription='{0}'", staticData.ShipType);
|
query += string.Format(" WHERE Id='{0}'", id);
|
||||||
query += string.Format(" WHERE id={0}", id);
|
|
||||||
|
|
||||||
con.ExecuteNonQuery(query);
|
con.ExecuteNonQuery(query);
|
||||||
}
|
}
|
||||||
else // Insert
|
else // Insert
|
||||||
{
|
{
|
||||||
query = string.Format("INSERT INTO aisstaticdata SET callsign='{0}', name='{1}', shiptype={2}, typeofdevice='{3}', shipdescription='{4}', stationid={5}, mmsi={6}, classb=1",
|
id = Guid.NewGuid();
|
||||||
staticData.Callsign,
|
query = string.Format("INSERT INTO aisstaticdata (Id, callsign, name, shiptype, classb, dimension, spare, aisstation_id, mmsi) VALUES ('{0}', '{1}', '{2}', {3}, {4}, {5}, {6}, '{7}', {8})",
|
||||||
staticData.Name,
|
id,
|
||||||
|
(staticData.Callsign ?? "").Replace("'","''"),
|
||||||
|
(staticData.Name ?? "").Replace("'","''"),
|
||||||
staticData.ShipTypeVal,
|
staticData.ShipTypeVal,
|
||||||
staticData.VendorId,
|
1,
|
||||||
staticData.ShipType,
|
staticData.Dimension,
|
||||||
|
staticData.Spare,
|
||||||
aisStation.Id,
|
aisStation.Id,
|
||||||
staticData.MMSI
|
staticData.MMSI
|
||||||
);
|
);
|
||||||
|
|
||||||
con.ExecuteNonQuery(query);
|
con.ExecuteNonQuery(query);
|
||||||
id = Convert.ToInt32(con.ExecuteScalar("SELECT LAST_INSERT_ID()"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,7 +386,7 @@ namespace bsmd.AISService.DB
|
|||||||
result.Add(ship);
|
result.Add(ship);
|
||||||
}
|
}
|
||||||
reader.Close();
|
reader.Close();
|
||||||
Trace.WriteLine(string.Format("AISStaticData: {0} ships loaded from DB", result.Count));
|
_log.InfoFormat("AISStaticData: {0} ships loaded from DB", result.Count);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ using System.Data;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
using bsmd.AISService.AIS;
|
using bsmd.AISService.AIS;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.DB
|
namespace bsmd.AISService.DB
|
||||||
{
|
{
|
||||||
@ -13,7 +14,6 @@ namespace bsmd.AISService.DB
|
|||||||
{
|
{
|
||||||
#region private members
|
#region private members
|
||||||
|
|
||||||
private Guid station_Id;
|
|
||||||
private string name;
|
private string name;
|
||||||
private bool active;
|
private bool active;
|
||||||
private string comport;
|
private string comport;
|
||||||
@ -30,6 +30,7 @@ namespace bsmd.AISService.DB
|
|||||||
private DateTime? lastPosTimestamp;
|
private DateTime? lastPosTimestamp;
|
||||||
private bool isDirty = false;
|
private bool isDirty = false;
|
||||||
private Dictionary<int, double> targets = new Dictionary<int, double>();
|
private Dictionary<int, double> targets = new Dictionary<int, double>();
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(AISStation));
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -101,7 +102,7 @@ namespace bsmd.AISService.DB
|
|||||||
this.comport,
|
this.comport,
|
||||||
this.name,
|
this.name,
|
||||||
this.baudrate,
|
this.baudrate,
|
||||||
this.station_Id);
|
this.Id);
|
||||||
|
|
||||||
if (con.ExecuteNonQuery(query) == 1)
|
if (con.ExecuteNonQuery(query) == 1)
|
||||||
{
|
{
|
||||||
@ -177,7 +178,7 @@ namespace bsmd.AISService.DB
|
|||||||
while (reader.Read())
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
AISStation station = new AISStation();
|
AISStation station = new AISStation();
|
||||||
station.station_Id = reader.GetGuid(0);
|
station.Id = reader.GetGuid(0);
|
||||||
station.name = reader.GetString(1);
|
station.name = reader.GetString(1);
|
||||||
station.active = reader.GetBoolean(2);
|
station.active = reader.GetBoolean(2);
|
||||||
station.latitude = (double) reader.GetInt32(3) / 600000;
|
station.latitude = (double) reader.GetInt32(3) / 600000;
|
||||||
@ -201,11 +202,11 @@ namespace bsmd.AISService.DB
|
|||||||
public static AISStation CreateStation(string name, DBConnector con)
|
public static AISStation CreateStation(string name, DBConnector con)
|
||||||
{
|
{
|
||||||
AISStation newStation = new AISStation();
|
AISStation newStation = new AISStation();
|
||||||
newStation.station_Id = Guid.NewGuid();
|
newStation.Id = Guid.NewGuid();
|
||||||
newStation.name = name;
|
newStation.name = name;
|
||||||
newStation.active = true;
|
newStation.active = true;
|
||||||
string query = string.Format("INSERT INTO aisstation SET Id='{0}', name='{1}',active=1",
|
string query = string.Format("INSERT INTO aisstation SET Id='{0}', name='{1}',active=1",
|
||||||
newStation.station_Id, newStation.name);
|
newStation.Id, newStation.name);
|
||||||
con.ExecuteNonQuery(query);
|
con.ExecuteNonQuery(query);
|
||||||
|
|
||||||
return newStation;
|
return newStation;
|
||||||
@ -243,8 +244,7 @@ namespace bsmd.AISService.DB
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Trace.WriteLine(string.Format("AIS_Telnet: cannot connect to host {0} port {1}: {2}",
|
_log.WarnFormat("AIS_Telnet: cannot connect to host {0} port {1}: {2}", station.TelnetHost ?? "", station.TelnetPort, ex.Message);
|
||||||
station.TelnetHost ?? "", station.TelnetPort, ex.Message));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ using System.Data;
|
|||||||
using System.Data.SqlClient;
|
using System.Data.SqlClient;
|
||||||
|
|
||||||
using bsmd.AISService.AIS;
|
using bsmd.AISService.AIS;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
namespace bsmd.AISService.DB
|
namespace bsmd.AISService.DB
|
||||||
{
|
{
|
||||||
@ -20,6 +21,7 @@ namespace bsmd.AISService.DB
|
|||||||
private List<AISWatchkeeper> watchkeeperShips = null;
|
private List<AISWatchkeeper> watchkeeperShips = null;
|
||||||
private List<AISStaticData> dbShips = null;
|
private List<AISStaticData> dbShips = null;
|
||||||
private Dictionary<string, AISStation> updateStations = null;
|
private Dictionary<string, AISStation> updateStations = null;
|
||||||
|
private static ILog _log = LogManager.GetLogger(typeof(DBConnector));
|
||||||
|
|
||||||
public DBConnector() { }
|
public DBConnector() { }
|
||||||
|
|
||||||
@ -65,21 +67,48 @@ namespace bsmd.AISService.DB
|
|||||||
if (!this.CheckConnection()) return null;
|
if (!this.CheckConnection()) return null;
|
||||||
|
|
||||||
SqlCommand cmd = new SqlCommand(query, this.dbCon);
|
SqlCommand cmd = new SqlCommand(query, this.dbCon);
|
||||||
return cmd.ExecuteReader();
|
SqlDataReader result = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = cmd.ExecuteReader();
|
||||||
|
}
|
||||||
|
catch(SqlException ex)
|
||||||
|
{
|
||||||
|
_log.ErrorFormat("ExecuteQuery: {0}", ex.Message);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ExecuteNonQuery(string query)
|
public int ExecuteNonQuery(string query)
|
||||||
{
|
{
|
||||||
if (!this.CheckConnection()) return 0;
|
if (!this.CheckConnection()) return 0;
|
||||||
SqlCommand cmd = new SqlCommand(query, this.dbCon);
|
SqlCommand cmd = new SqlCommand(query, this.dbCon);
|
||||||
return cmd.ExecuteNonQuery();
|
int result = -1;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
catch(SqlException ex)
|
||||||
|
{
|
||||||
|
_log.ErrorFormat("ExecuteNonQuery: [{0}] {1} ", query, ex.Message);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ExecuteScalar(string query)
|
public object ExecuteScalar(string query)
|
||||||
{
|
{
|
||||||
if (!this.CheckConnection()) return 0;
|
if (!this.CheckConnection()) return 0;
|
||||||
SqlCommand cmd = new SqlCommand(query, this.dbCon);
|
SqlCommand cmd = new SqlCommand(query, this.dbCon);
|
||||||
return cmd.ExecuteScalar();
|
object result = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = cmd.ExecuteScalar();
|
||||||
|
}
|
||||||
|
catch(SqlException ex)
|
||||||
|
{
|
||||||
|
_log.ErrorFormat("ExecuteScalar: [{0}] {1} ", query, ex.Message);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Open()
|
public bool Open()
|
||||||
@ -94,7 +123,7 @@ namespace bsmd.AISService.DB
|
|||||||
}
|
}
|
||||||
catch (SqlException anException)
|
catch (SqlException anException)
|
||||||
{
|
{
|
||||||
Trace.WriteLine(string.Format("cannot open SQL DB connection: {0}", anException.Message));
|
_log.ErrorFormat("cannot open SQL DB connection: {0}", anException.Message);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -120,9 +149,9 @@ namespace bsmd.AISService.DB
|
|||||||
if (this.updateStations == null)
|
if (this.updateStations == null)
|
||||||
{
|
{
|
||||||
this.updateStations = new Dictionary<string, AISStation>();
|
this.updateStations = new Dictionary<string, AISStation>();
|
||||||
Trace.WriteLine("loading stations..");
|
_log.Info("loading stations..");
|
||||||
List<AISStation> stations = AISStation.LoadStations(this);
|
List<AISStation> stations = AISStation.LoadStations(this);
|
||||||
Trace.WriteLine(string.Format("{0} stations loaded", stations.Count));
|
_log.InfoFormat("{0} stations loaded", stations.Count);
|
||||||
foreach (AISStation station in stations)
|
foreach (AISStation station in stations)
|
||||||
if (!updateStations.ContainsKey(station.Name))
|
if (!updateStations.ContainsKey(station.Name))
|
||||||
updateStations.Add(station.Name, station);
|
updateStations.Add(station.Name, station);
|
||||||
@ -140,7 +169,7 @@ namespace bsmd.AISService.DB
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Trace.WriteLine(string.Format("last pos report is null for target {0}", target.MMSI));
|
_log.InfoFormat("last pos report is null for target {0}", target.MMSI);
|
||||||
}
|
}
|
||||||
if (target.LastStaticData != null)
|
if (target.LastStaticData != null)
|
||||||
{
|
{
|
||||||
@ -153,8 +182,9 @@ namespace bsmd.AISService.DB
|
|||||||
}
|
}
|
||||||
|
|
||||||
target.UpdateDB = false; // reset update flag
|
target.UpdateDB = false; // reset update flag
|
||||||
// Watchkeeper check
|
|
||||||
|
|
||||||
|
// Watchkeeper check
|
||||||
|
/*
|
||||||
if (this.watchkeeperShips == null)
|
if (this.watchkeeperShips == null)
|
||||||
this.watchkeeperShips = AISWatchkeeper.GetWatchkeeperShips(this);
|
this.watchkeeperShips = AISWatchkeeper.GetWatchkeeperShips(this);
|
||||||
|
|
||||||
@ -170,7 +200,7 @@ namespace bsmd.AISService.DB
|
|||||||
if (!target.IsWatchkeeperShip.HasValue) // didn't find it
|
if (!target.IsWatchkeeperShip.HasValue) // didn't find it
|
||||||
target.IsWatchkeeperShip = false;
|
target.IsWatchkeeperShip = false;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +230,7 @@ namespace bsmd.AISService.DB
|
|||||||
}
|
}
|
||||||
catch (SqlException ex)
|
catch (SqlException ex)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Trace.WriteLine(ex.ToString());
|
_log.Error(ex.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.dbCon.State == System.Data.ConnectionState.Open;
|
return this.dbCon.State == System.Data.ConnectionState.Open;
|
||||||
|
|||||||
@ -22,6 +22,9 @@ namespace bsmd.AISService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
log4net.Config.XmlConfigurator.Configure();
|
||||||
|
|
||||||
if (Environment.UserInteractive)
|
if (Environment.UserInteractive)
|
||||||
{
|
{
|
||||||
if (args.Length > 0)
|
if (args.Length > 0)
|
||||||
@ -85,7 +88,7 @@ namespace bsmd.AISService
|
|||||||
if (ex.InnerException != null && ex.InnerException.GetType() == typeof(Win32Exception))
|
if (ex.InnerException != null && ex.InnerException.GetType() == typeof(Win32Exception))
|
||||||
{
|
{
|
||||||
Win32Exception wex = (Win32Exception)ex.InnerException;
|
Win32Exception wex = (Win32Exception)ex.InnerException;
|
||||||
Console.WriteLine("Error(0x{0:X}): Service already installed!", wex.ErrorCode);
|
Console.WriteLine("Error {0}: {1}", wex.ErrorCode, wex.Message);
|
||||||
return wex.ErrorCode;
|
return wex.ErrorCode;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
1
AIS/bsmd.AISService/ProjectInstaller.Designer.cs
generated
1
AIS/bsmd.AISService/ProjectInstaller.Designer.cs
generated
@ -33,6 +33,7 @@
|
|||||||
//
|
//
|
||||||
// serviceProcessInstallerAIS
|
// serviceProcessInstallerAIS
|
||||||
//
|
//
|
||||||
|
this.serviceProcessInstallerAIS.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
|
||||||
this.serviceProcessInstallerAIS.Password = null;
|
this.serviceProcessInstallerAIS.Password = null;
|
||||||
this.serviceProcessInstallerAIS.Username = null;
|
this.serviceProcessInstallerAIS.Username = null;
|
||||||
//
|
//
|
||||||
|
|||||||
@ -118,7 +118,7 @@
|
|||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<metadata name="serviceProcessInstallerAIS.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="serviceProcessInstallerAIS.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>17, 17</value>
|
<value>17, 54</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
<metadata name="serviceInstallerAIS.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="serviceInstallerAIS.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>196, 17</value>
|
<value>196, 17</value>
|
||||||
|
|||||||
@ -102,7 +102,9 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="App.config" />
|
<None Include="App.config">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</None>
|
||||||
<None Include="bsmd.AISService.licenseheader" />
|
<None Include="bsmd.AISService.licenseheader" />
|
||||||
<None Include="bsmdKey.snk" />
|
<None Include="bsmdKey.snk" />
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
|||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user