| @@ -1,45 +1,92 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Threading; | ||
| using Netronics.Template.Http; | ||
| using Netronics.Template.Http.Handler; | ||
| using Netronics.Template.Http.SocketIO; | ||
| using Newtonsoft.Json; | ||
| using Newtonsoft.Json.Linq; | ||
|
|
||
| namespace WebServer | ||
| { | ||
| class Program | ||
| { | ||
| public static readonly AutoResetEvent ExitEvent = new AutoResetEvent(false); | ||
| private static readonly List<ISocketIO> UserList = new List<ISocketIO>(); | ||
| static void Main(string[] args) | ||
| { | ||
| AppDomain.CurrentDomain.UnhandledException += (s, e) => | ||
| { | ||
| }; | ||
|
|
||
| var handler = new HttpHandler(); | ||
| handler.AddStatic("^/$", "./www/index.html"); | ||
| handler.AddStatic("^(.*).css$", "./www/{1}.css"); | ||
| handler.AddStatic("^/script/(.*)$", "./www/script/{1}"); | ||
| handler.AddStatic("^/file/(.*)$", "./www/test/file/{1}"); | ||
|
|
||
| handler.AddDynamic("^/test.web$", TestModule.TestController.TestMain); | ||
| handler.AddWebSocket("^/echo$", strings => new WebSocketHandler()); | ||
| handler.AddJSON("^/test.json$", strings => | ||
| { | ||
| dynamic json = new JObject(); | ||
| json.test = "abcd"; | ||
| json.test2 = 123; | ||
| json.a = new JArray(strings); | ||
| return json; | ||
| }); | ||
| var io = new SocketIO(); | ||
| io.On("connection", s => | ||
| { | ||
| var socket = s as ISocketIO; | ||
| lock (UserList) | ||
| { | ||
| UserList.Add(socket); | ||
|
|
||
| dynamic obj = new JObject(); | ||
| obj.name = "System"; | ||
| obj.msg = socket.ToString() + " 접속"; | ||
| foreach (var sock in UserList) | ||
| { | ||
| sock.Emit("chat", new JArray(new object[] { obj })); | ||
| } | ||
| } | ||
|
|
||
| socket.On("chat", o => | ||
| { | ||
| dynamic obj = new JObject(); | ||
| obj.name = socket.ToString(); | ||
| obj.msg = o[0].msg; | ||
| lock (UserList) | ||
| { | ||
| foreach (var sock in UserList) | ||
| { | ||
| sock.Emit("chat", new JArray(new object[] { obj })); | ||
| } | ||
| } | ||
| }); | ||
| }); | ||
| io.On("disconnect", o => | ||
| { | ||
| var socket = o as ISocketIO; | ||
| lock (UserList) | ||
| { | ||
| UserList.Remove(socket); | ||
|
|
||
| dynamic obj = new JObject(); | ||
| obj.name = "System"; | ||
| obj.msg = socket.ToString() + " 접속 종료"; | ||
| foreach (var sock in UserList) | ||
| { | ||
| sock.Emit("chat", new JArray(new object[] { obj })); | ||
| } | ||
| } | ||
| }); | ||
| handler.AddSocketIO(io); | ||
|
|
||
| var netronics = new Netronics.Netronics(new HttpsProperties(() => handler)); | ||
| netronics.Start(); | ||
| ExitEvent.WaitOne(); | ||
| } | ||
| } | ||
| } |
| @@ -22,7 +22,7 @@ protected bool ReceivePacket(byte[] buffer, int len) | ||
| return true; | ||
| } | ||
|
|
||
| protected virtual void Disconnected() | ||
| { | ||
| lock (_packetBuffer) | ||
| { | ||
| @@ -73,6 +73,13 @@ public override void Disconnect() | ||
| }, null); | ||
| } | ||
|
|
||
| protected override void Disconnected() | ||
| { | ||
| base.Disconnected(); | ||
| _socket.Dispose(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| public override void SendMessage(dynamic message) | ||
| { | ||
| @@ -0,0 +1,134 @@ | ||
| using System; | ||
| using System.Net.Security; | ||
| using System.Net.Sockets; | ||
| using System.Threading; | ||
|
|
||
| namespace Netronics.Channel.Channel | ||
| { | ||
| public class SslChannel : Channel | ||
| { | ||
| public static SslChannel CreateChannel(Socket socket, System.Security.Cryptography.X509Certificates.X509Certificate certificate) | ||
| { | ||
| var channel = new SslChannel(socket); | ||
| channel._stream.AuthenticateAsServer(certificate); | ||
| return channel; | ||
| } | ||
|
|
||
| public static SslChannel CreateChannel(Socket socket, string host) | ||
| { | ||
| var channel = new SslChannel(socket); | ||
| channel._stream.AuthenticateAsClient(host); | ||
| return channel; | ||
| } | ||
|
|
||
| private readonly byte[] _originalPacketBuffer = new byte[512]; | ||
| private readonly Socket _socket; | ||
| private readonly SslStream _stream; | ||
|
|
||
| private object _tag; | ||
|
|
||
| private SslChannel(Socket socket) | ||
| { | ||
| _socket = socket; | ||
| _stream = new SslStream(new NetworkStream(socket, true)); | ||
| } | ||
|
|
||
| public Socket GetSocket() | ||
| { | ||
| return _socket; | ||
| } | ||
|
|
||
| public override string ToString() | ||
| { | ||
| return _socket.RemoteEndPoint.ToString(); | ||
| } | ||
|
|
||
| protected override void BeginReceive() | ||
| { | ||
| try | ||
| { | ||
| _stream.BeginRead(_originalPacketBuffer, 0, 512, ReadCallback, null); | ||
| } | ||
| catch (SocketException) | ||
| { | ||
| Disconnect(); | ||
| } | ||
| } | ||
|
|
||
| private void ReadCallback(IAsyncResult ar) | ||
| { | ||
| int len; | ||
| try | ||
| { | ||
| len = _stream.EndRead(ar); | ||
| if (len == 0) | ||
| throw new SocketException(); | ||
| } | ||
| catch (SocketException) | ||
| { | ||
| ThreadPool.QueueUserWorkItem((o) => Disconnect()); | ||
| return; | ||
| } | ||
|
|
||
| ReceivePacket(_originalPacketBuffer, len); | ||
| } | ||
|
|
||
| public override void Disconnect() | ||
| { | ||
| _socket.BeginDisconnect(false, ar => | ||
| { | ||
| if (GetHandler() != null) | ||
| GetHandler().Disconnected(this); | ||
| Disconnected(); | ||
| }, null); | ||
| } | ||
|
|
||
| protected override void Disconnected() | ||
| { | ||
| base.Disconnected(); | ||
| _socket.Dispose(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| public override void SendMessage(dynamic message) | ||
| { | ||
| PacketBuffer buffer = GetProtocol().GetEncoder().Encode(this, message); | ||
|
|
||
| if (buffer == null) | ||
| return; | ||
| byte[] o = buffer.GetBytes(); | ||
| buffer.Dispose(); | ||
|
|
||
| try | ||
| { | ||
| _stream.BeginWrite(o, 0, o.Length, SendCallback, null); | ||
| } | ||
| catch (SocketException) | ||
| { | ||
| } | ||
| } | ||
|
|
||
| public override object SetTag(object tag) | ||
| { | ||
| _tag = tag; | ||
| return _tag; | ||
| } | ||
|
|
||
| public override object GetTag() | ||
| { | ||
| return _tag; | ||
| } | ||
|
|
||
| private void SendCallback(IAsyncResult ar) | ||
| { | ||
| try | ||
| { | ||
| _socket.EndSend(ar); | ||
| } | ||
| catch (SocketException) | ||
| { | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,75 @@ | ||
| using System; | ||
| using System.Net; | ||
| using System.Net.Sockets; | ||
| using System.Security.Cryptography.X509Certificates; | ||
| using Netronics.Channel; | ||
| using Netronics.Channel.Channel; | ||
| using Netronics.Protocol; | ||
| using Netronics.Protocol.PacketEncoder; | ||
| using Netronics.Protocol.PacketEncoder.Http; | ||
| using Netronics.Protocol.PacketEncryptor; | ||
|
|
||
| namespace Netronics.Template.Http | ||
| { | ||
| public class HttpsProperties : IProperties, IProtocol, IChannelPipe | ||
| { | ||
| private static readonly HttpEncoder Encoder = new HttpEncoder(); | ||
| private static readonly HttpDecoder Decoder = new HttpDecoder(); | ||
| private readonly Func<IChannelHandler> _handler; | ||
| protected IPEndPoint IpEndPoint = new IPEndPoint(IPAddress.Any, 0); | ||
|
|
||
|
|
||
| public HttpsProperties(Func<IChannelHandler> handler, int port = 443) | ||
| { | ||
| IpEndPoint = new IPEndPoint(IPAddress.Any, port); | ||
| _handler = handler; | ||
| } | ||
|
|
||
| public IChannel CreateChannel(Netronics netronics, Socket socket) | ||
| { | ||
| SslChannel channel = SslChannel.CreateChannel(socket, X509Certificate.CreateFromCertFile("test.cert")); | ||
| channel.SetProtocol(this); | ||
| channel.SetHandler(_handler()); | ||
| return channel; | ||
| } | ||
|
|
||
| public IPacketEncryptor GetEncryptor() | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| public IPacketDecryptor GetDecryptor() | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| public IPacketEncoder GetEncoder() | ||
| { | ||
| return Encoder; | ||
| } | ||
|
|
||
| public IPacketDecoder GetDecoder() | ||
| { | ||
| return Decoder; | ||
| } | ||
|
|
||
|
|
||
| public void OnStartEvent(Netronics netronics, EventArgs eventArgs) | ||
| { | ||
| } | ||
|
|
||
| public void OnStopEvent(Netronics netronics, EventArgs eventArgs) | ||
| { | ||
| } | ||
|
|
||
| public IPEndPoint GetIPEndPoint() | ||
| { | ||
| return IpEndPoint; | ||
| } | ||
|
|
||
| public IChannelPipe GetChannelPipe() | ||
| { | ||
| return this; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,40 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using System.Linq; | ||
| using System.Text; | ||
|
|
||
| namespace Service.Coroutine | ||
| { | ||
| class Co | ||
| { | ||
| [ThreadStatic] | ||
| public static Coroutine Current; | ||
|
|
||
| // 중간에서 yield할 수 있는 로직은 반드시 yield return Co.Call 형태를 사용해야 한다. | ||
| public static IYield Call(IEnumerator<IYield> e) | ||
| { | ||
| return new NestedYield(e); | ||
| } | ||
|
|
||
| // k초 뒤에 현재 코루틴을 재개하도록 스케줄링 | ||
| // 이런 식으로 IO 함수도 만들 수 있다. | ||
| // IO가 완료되면 실행하도록 콜백을 등록하게 하면 됨 | ||
|
|
||
| /* | ||
| public static IEnumerator<IYield> Sleep(int t) | ||
| { | ||
| Coroutine c = Current; | ||
| /*Debug.Assert(c != null); | ||
| // 스케줄러 복잡하게 짜기 귀찮으니 대충 Sleep했다고 치고 실행 큐 마지막에 등록 | ||
| Scheduler.Schedule( | ||
| delegate() { c.Resume(); }, | ||
| t);/// | ||
| yield return new NonNestedYield(); | ||
| } | ||
| */ | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,26 @@ | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Service.Coroutine | ||
| { | ||
| class Coroutine | ||
| { | ||
| public delegate IEnumerator<IYield> CoroutineEntrance(); | ||
|
|
||
| public Coroutine(CoroutineEntrance entrance) | ||
| { | ||
| Co.Current = this; | ||
| y = Co.Call(entrance()); | ||
| Co.Current = null; | ||
| } | ||
|
|
||
| public bool Resume() | ||
| { | ||
| Co.Current = this; | ||
| bool ret = y.Resume(); | ||
| Co.Current = null; | ||
| return ret; | ||
| } | ||
|
|
||
| private IYield y; | ||
| } | ||
| } |
| @@ -0,0 +1,7 @@ | ||
| namespace Service.Coroutine | ||
| { | ||
| public interface IYield | ||
| { | ||
| bool Resume(); | ||
| } | ||
| } |
| @@ -0,0 +1,31 @@ | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Service.Coroutine | ||
| { | ||
| class NestedYield : IYield | ||
| { | ||
| public NestedYield(IEnumerator<IYield> e) | ||
| { | ||
| _e = e; | ||
| _valid = e.MoveNext(); | ||
| } | ||
|
|
||
| public bool Resume() | ||
| { | ||
| if (!_valid) | ||
| { | ||
| return false; | ||
| } | ||
| if (_e.Current.Resume()) | ||
| { | ||
| return true; | ||
| } | ||
| _valid = _e.MoveNext(); | ||
| return _valid; | ||
| } | ||
|
|
||
| private readonly IEnumerator<IYield> _e; | ||
| private bool _valid; | ||
|
|
||
| } | ||
| } |
| @@ -0,0 +1,16 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Text; | ||
|
|
||
| namespace Service.Coroutine | ||
| { | ||
| class NonNestedYield : IYield | ||
| { | ||
| public bool Resume() | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,23 @@ | ||
| using Netronics.Channel; | ||
| using Netronics.Channel.Channel; | ||
|
|
||
| namespace Service.Manager | ||
| { | ||
| class Handler : IChannelHandler | ||
| { | ||
| public void Connected(IChannel channel) | ||
| { | ||
| } | ||
|
|
||
| public void Disconnected(IChannel channel) | ||
| { | ||
| } | ||
|
|
||
| public void MessageReceive(IChannel channel, dynamic message) | ||
| { | ||
| if(message.type == "") | ||
| { | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,43 @@ | ||
| using Netronics; | ||
| using Netronics.Channel.Channel; | ||
| using Netronics.Protocol.PacketEncoder; | ||
| using Service.Manager.Packets; | ||
|
|
||
| namespace Service.Manager | ||
| { | ||
| class PacketEncoder : IPacketEncoder, IPacketDecoder | ||
| { | ||
| public PacketBuffer Encode(IChannel channel, dynamic data) | ||
| { | ||
| if(data is Ping) | ||
| { | ||
| var packet = new PacketBuffer(); | ||
| packet.WriteByte(0); | ||
| return packet; | ||
| } | ||
|
|
||
| if(data is JoinService) | ||
| { | ||
| var packet = new PacketBuffer(); | ||
| packet.WriteByte(1); | ||
| return packet; | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| public dynamic Decode(IChannel channel, PacketBuffer buffer) | ||
| { | ||
| buffer.BeginBufferIndex(); | ||
| if (buffer.AvailableBytes() < 1) | ||
| return null; | ||
|
|
||
| byte type = buffer.ReadByte(); | ||
| if(type == 0) | ||
| { | ||
| buffer.EndBufferIndex(); | ||
| return new Ping(); | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,9 @@ | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Service.Manager.Packets | ||
| { | ||
| class JoinService | ||
| { | ||
| public string Name; | ||
| } | ||
| } |
| @@ -0,0 +1,6 @@ | ||
| namespace Service.Manager.Packets | ||
| { | ||
| class Ping | ||
| { | ||
| } | ||
| } |
| @@ -0,0 +1,81 @@ | ||
| using System; | ||
| using System.Net; | ||
| using System.Net.Sockets; | ||
| using Netronics; | ||
| using Netronics.Channel; | ||
| using Netronics.Channel.Channel; | ||
| using Netronics.Protocol; | ||
| using Netronics.Protocol.PacketEncoder; | ||
| using Netronics.Protocol.PacketEncoder.Bson; | ||
| using Netronics.Protocol.PacketEncryptor; | ||
| using Netronics.Template.Http.Handler; | ||
|
|
||
| namespace Service.Manager | ||
| { | ||
| class ServiceManager : IProperties, IChannelPipe, IProtocol | ||
| { | ||
| private static ServiceManager _manager; | ||
|
|
||
| private static readonly BsonEncoder Encoder = new BsonEncoder(); | ||
| private static readonly BsonDecoder Decoder = new BsonDecoder(); | ||
|
|
||
| private readonly Netronics.Netronics _netronics; | ||
|
|
||
| public static void Load(string name) | ||
| { | ||
| _manager = new ServiceManager(); | ||
| } | ||
|
|
||
| public ServiceManager() | ||
| { | ||
| _netronics = new Netronics.Netronics(this); | ||
| _netronics.Start(); | ||
| } | ||
|
|
||
| public void OnStartEvent(Netronics.Netronics netronics, EventArgs eventArgs) | ||
| { | ||
| } | ||
|
|
||
| public void OnStopEvent(Netronics.Netronics netronics, EventArgs eventArgs) | ||
| { | ||
| } | ||
|
|
||
| public IPEndPoint GetIPEndPoint() | ||
| { | ||
| return new IPEndPoint(IPAddress.Any, 1005); | ||
| } | ||
|
|
||
| public IChannelPipe GetChannelPipe() | ||
| { | ||
| return this; | ||
| } | ||
|
|
||
| public IChannel CreateChannel(Netronics.Netronics netronics, Socket socket) | ||
| { | ||
| var channel = SocketChannel.CreateChannel(socket); | ||
| channel.SetProtocol(this); | ||
| channel.SetHandler(new Handler()); | ||
| return channel; | ||
| } | ||
|
|
||
| public IPacketEncryptor GetEncryptor() | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| public IPacketDecryptor GetDecryptor() | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| public IPacketEncoder GetEncoder() | ||
| { | ||
| return Encoder; | ||
| } | ||
|
|
||
| public IPacketDecoder GetDecoder() | ||
| { | ||
| return Decoder; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,66 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.IO; | ||
| using System.Threading; | ||
| using Service.Service.Loader; | ||
|
|
||
| namespace Service | ||
| { | ||
| class Program | ||
| { | ||
| public static readonly AutoResetEvent ExitEvent = new AutoResetEvent(false); | ||
|
|
||
| static void ServiceLoad(string servicesFilePath) | ||
| { | ||
| if (!File.Exists(servicesFilePath)) | ||
| throw new Exception("system.ns 파일이 존재하지 않습니다."); | ||
|
|
||
| var servicesDirectory = new FileInfo(servicesFilePath).DirectoryName; | ||
| var serviceList = new List<string>(); | ||
| foreach (var line in File.ReadLines(servicesFilePath)) | ||
| { | ||
| if (serviceList.Exists((str) => str == line.ToLower())) | ||
| throw new Exception("system.ns에 중복된 서비스 이름이 존재합니다."); | ||
|
|
||
| serviceList.Add(line.ToLower()); | ||
| if (line.ToLower() == "servicemanager") | ||
| { | ||
| Manager.ServiceManager.Load(servicesDirectory); | ||
| continue; | ||
| } | ||
|
|
||
| if (!File.Exists(servicesDirectory + "/" + line)) | ||
| throw new Exception(line + " 서비스를 찾을 수 없습니다."); | ||
|
|
||
|
|
||
| ServiceLoader.Load(servicesDirectory, line); | ||
| } | ||
| } | ||
|
|
||
| static void Main(string[] args) | ||
| { | ||
| //차후 명령처리를 위해서... | ||
|
|
||
| var servicesFilePath = AppDomain.CurrentDomain.BaseDirectory + "system.ns"; | ||
| if (args.Length > 0) | ||
| servicesFilePath = args[args.Length - 1]; | ||
|
|
||
| //테스트 | ||
| servicesFilePath = @"C:\Users\Sanghyuck\Projects\Parfe Server\bin\system.ns"; | ||
|
|
||
| ServiceLoad(servicesFilePath); | ||
|
|
||
| /* | ||
| string host_name = Dns.GetHostName(); | ||
| IPHostEntry ips = Dns.GetHostEntry(host_name); | ||
| foreach (IPAddress ip in ips.AddressList) | ||
| { | ||
| Console.Write(ip.ToString()); | ||
| }*/ | ||
|
|
||
|
|
||
| ExitEvent.WaitOne(); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,36 @@ | ||
| using System.Reflection; | ||
| using System.Runtime.CompilerServices; | ||
| using System.Runtime.InteropServices; | ||
|
|
||
| // 어셈블리의 일반 정보는 다음 특성 집합을 통해 제어됩니다. | ||
| // 어셈블리와 관련된 정보를 수정하려면 | ||
| // 이 특성 값을 변경하십시오. | ||
| [assembly: AssemblyTitle("Service")] | ||
| [assembly: AssemblyDescription("")] | ||
| [assembly: AssemblyConfiguration("")] | ||
| [assembly: AssemblyCompany("")] | ||
| [assembly: AssemblyProduct("Service")] | ||
| [assembly: AssemblyCopyright("Copyright © 2012")] | ||
| [assembly: AssemblyTrademark("")] | ||
| [assembly: AssemblyCulture("")] | ||
|
|
||
| // ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에 | ||
| // 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면 | ||
| // 해당 형식에 대해 ComVisible 특성을 true로 설정하십시오. | ||
| [assembly: ComVisible(false)] | ||
|
|
||
| // 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다. | ||
| [assembly: Guid("388e6913-4149-4658-92a6-e73f47211ed3")] | ||
|
|
||
| // 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다. | ||
| // | ||
| // 주 버전 | ||
| // 부 버전 | ||
| // 빌드 번호 | ||
| // 수정 버전 | ||
| // | ||
| // 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 버전이 자동으로 | ||
| // 지정되도록 할 수 있습니다. | ||
| // [assembly: AssemblyVersion("1.0.*")] | ||
| [assembly: AssemblyVersion("1.0.0.0")] | ||
| [assembly: AssemblyFileVersion("1.0.0.0")] |
| @@ -0,0 +1,84 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project ToolsVersion="4.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>{4CA1EF2C-573E-4885-B167-56AD75F6B5F1}</ProjectGuid> | ||
| <OutputType>Exe</OutputType> | ||
| <AppDesignerFolder>Properties</AppDesignerFolder> | ||
| <RootNamespace>Service</RootNamespace> | ||
| <AssemblyName>Service</AssemblyName> | ||
| <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> | ||
| <FileAlignment>512</FileAlignment> | ||
| <TargetFrameworkProfile /> | ||
| </PropertyGroup> | ||
| <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> | ||
| <PlatformTarget>x86</PlatformTarget> | ||
| <DebugSymbols>true</DebugSymbols> | ||
| <DebugType>full</DebugType> | ||
| <Optimize>false</Optimize> | ||
| <OutputPath>..\..\bin\Release\</OutputPath> | ||
| <DefineConstants>DEBUG;TRACE</DefineConstants> | ||
| <ErrorReport>prompt</ErrorReport> | ||
| <WarningLevel>4</WarningLevel> | ||
| </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> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <Reference Include="Microsoft.CSharp" /> | ||
| <Reference Include="System" /> | ||
| <Reference Include="System.Core" /> | ||
| <Reference Include="System.Xml.Linq" /> | ||
| <Reference Include="System.Data.DataSetExtensions" /> | ||
| <Reference Include="System.Data" /> | ||
| <Reference Include="System.Xml" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <Compile Include="Manager\Handler.cs" /> | ||
| <Compile Include="Manager\PacketEncoder.cs" /> | ||
| <Compile Include="Manager\Packets\JoinService.cs" /> | ||
| <Compile Include="Manager\Packets\Ping.cs" /> | ||
| <Compile Include="Manager\ServiceManager.cs" /> | ||
| <Compile Include="Service\Command.cs" /> | ||
| <Compile Include="Coroutine\Co.cs" /> | ||
| <Compile Include="Coroutine\Coroutine.cs" /> | ||
| <Compile Include="Coroutine\IYield.cs" /> | ||
| <Compile Include="Coroutine\NestedYield.cs" /> | ||
| <Compile Include="Coroutine\NonNestedYield.cs" /> | ||
| <Compile Include="Service\Entity.cs" /> | ||
| <Compile Include="Service\IServiceInfo.cs" /> | ||
| <Compile Include="Service\Loader\ManagerProcessor.cs" /> | ||
| <Compile Include="Service\LocalService.cs" /> | ||
| <Compile Include="Program.cs" /> | ||
| <Compile Include="Properties\AssemblyInfo.cs" /> | ||
| <Compile Include="Service\Service.cs" /> | ||
| <Compile Include="Service\Loader\ServiceLoader.cs" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <ProjectReference Include="..\Framework\Netronics.csproj"> | ||
| <Project>{394898C7-12EE-478A-AD9A-7377B5DCC081}</Project> | ||
| <Name>Netronics</Name> | ||
| </ProjectReference> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <None Include="app.config" /> | ||
| </ItemGroup> | ||
| <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> |
| @@ -0,0 +1,9 @@ | ||
| using System; | ||
|
|
||
| namespace Service.Service | ||
| { | ||
| [AttributeUsage(AttributeTargets.Method)] | ||
| public class Command : Attribute | ||
| { | ||
| } | ||
| } |
| @@ -0,0 +1,64 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Threading; | ||
| using Service.Coroutine; | ||
|
|
||
| namespace Service.Service | ||
| { | ||
| public class Entity | ||
| { | ||
| private static readonly ThreadLocal<Stack<Entity>> Stack = new ThreadLocal<Stack<Entity>>(() => new Stack<Entity>()); | ||
|
|
||
| private readonly LocalService _service; | ||
| private readonly string _uid; | ||
|
|
||
| public static Entity CreateEntity(LocalService service, string uid) | ||
| { | ||
| return new Entity(service, uid); | ||
| } | ||
|
|
||
| public Entity(LocalService service, string uid) | ||
| { | ||
| _service = service; | ||
| _uid = uid; | ||
| } | ||
|
|
||
| public LocalService GetLocalService() | ||
| { | ||
| return _service; | ||
| } | ||
|
|
||
| public static Entity GetEntity() | ||
| { | ||
| try | ||
| { | ||
| return Stack.Value.Peek(); | ||
| } | ||
| catch (InvalidOperationException) | ||
| { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| public IYield Call<T>(Func<T, IEnumerator<IYield>> func) where T : class | ||
| { | ||
| var t = _service as T; | ||
| if(t == null) | ||
| throw new Exception("등록된 서비스가 Call 대상을 상속하고 있지 않습니다."); | ||
| Stack.Value.Push(this); | ||
| var o = new NestedYield(func(t)); //내부에서 패킷 전송후 yield return new NonNestedYield(); | ||
| Stack.Value.Pop(); | ||
| return o; | ||
| } | ||
|
|
||
| public IEnumerator<IYield> Call<T>(Action<T> func) | ||
| { | ||
| return null;/* | ||
| Call<T>(o => | ||
| { | ||
| func(o); | ||
| return null; | ||
| });*/ | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,8 @@ | ||
| namespace Service.Service | ||
| { | ||
| public interface IServiceInfo | ||
| { | ||
| string GetServiceName(); | ||
| LocalService GetService(); | ||
| } | ||
| } |
| @@ -0,0 +1,120 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Net; | ||
| using System.Net.NetworkInformation; | ||
| using System.Net.Sockets; | ||
| using Netronics; | ||
| using Netronics.Channel; | ||
| using Netronics.Channel.Channel; | ||
| using Netronics.Protocol; | ||
| using Netronics.Protocol.PacketEncoder; | ||
| using Netronics.Protocol.PacketEncryptor; | ||
|
|
||
| namespace Service.Service.Loader | ||
| { | ||
| class ManagerProcessor : IProperties, IChannelPipe, IProtocol | ||
| { | ||
| private readonly Netronics.Netronics _manager; | ||
| private ServiceLoader _loader; | ||
|
|
||
| private readonly string[] _host; | ||
| private IPEndPoint _managerIPEndPoint; | ||
|
|
||
| public ManagerProcessor(ServiceLoader loader, string[] host) | ||
| { | ||
| _loader = loader; | ||
| _host = host; | ||
| _manager = new Client(this); | ||
| var address = GetIPAddress(); | ||
|
|
||
| Connect(); | ||
| _manager.Start(); | ||
| } | ||
|
|
||
| private List<IPAddress> GetIPAddress() | ||
| { | ||
| var addresses = new List<IPAddress>(); | ||
|
|
||
| var adapters = NetworkInterface.GetAllNetworkInterfaces(); | ||
| foreach (var adapter in adapters) | ||
| { | ||
| var properties = adapter.GetIPProperties(); | ||
| foreach (var uniCast in properties.UnicastAddresses) | ||
| { | ||
| if (!IPAddress.IsLoopback(uniCast.Address)) | ||
| addresses.Add(uniCast.Address); | ||
| } | ||
| } | ||
| return addresses; | ||
| } | ||
|
|
||
| private bool Connect() | ||
| { | ||
| var host = GetHost(); | ||
| if (host == null) | ||
| return false; | ||
| _managerIPEndPoint = new IPEndPoint(IPAddress.Parse(host), 1005); | ||
| return true; | ||
| } | ||
|
|
||
| private string GetHost() | ||
| { | ||
| foreach (var host in _host) | ||
| { | ||
| try | ||
| { | ||
| var clnt = new TcpClient(host, 1005); | ||
| clnt.Close(); | ||
| return host; | ||
| } | ||
| catch | ||
| { | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| public IPEndPoint GetIPEndPoint() | ||
| { | ||
| return _managerIPEndPoint; | ||
| } | ||
|
|
||
| public IChannelPipe GetChannelPipe() | ||
| { | ||
| return this; | ||
| } | ||
|
|
||
| public void OnStartEvent(Netronics.Netronics netronics, EventArgs eventArgs) | ||
| { | ||
| } | ||
|
|
||
| public void OnStopEvent(Netronics.Netronics netronics, EventArgs eventArgs) | ||
| { | ||
| } | ||
|
|
||
| public IChannel CreateChannel(Netronics.Netronics netronics, Socket socket) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| public IPacketEncryptor GetEncryptor() | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| public IPacketDecryptor GetDecryptor() | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| public IPacketEncoder GetEncoder() | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| public IPacketDecoder GetDecoder() | ||
| { | ||
| return null; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,33 @@ | ||
| using System; | ||
| using System.IO; | ||
| using System.Reflection; | ||
|
|
||
| namespace Service.Service.Loader | ||
| { | ||
| class ServiceLoader | ||
| { | ||
| private IServiceInfo _info; | ||
| private ManagerProcessor _manager; | ||
|
|
||
| private LocalService _service; | ||
|
|
||
| public static void Load(string path, string name) | ||
| { | ||
| new ServiceLoader(path, name); | ||
| } | ||
|
|
||
| private ServiceLoader(string path, string name) | ||
| { | ||
| Assembly asm = Assembly.LoadFrom(path + "/" + name); | ||
| var info = asm.GetType(asm.FullName.Substring(0, asm.FullName.IndexOf(",")) + ".ServiceInfo"); | ||
| if(info == null || !typeof(IServiceInfo).IsAssignableFrom(info)) | ||
| throw new Exception(asm.FullName.Substring(0, asm.FullName.IndexOf(",")) + ".ServiceInfo가 존재하지 않거나 IServiceInfo를 상속받지 않습니다."); | ||
|
|
||
|
|
||
| _info = (IServiceInfo)Activator.CreateInstance(info); | ||
| _service = _info.GetService(); | ||
|
|
||
| _manager = new ManagerProcessor(this, File.ReadAllLines(path + "/manager.ns")); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,17 @@ | ||
| namespace Service.Service | ||
| { | ||
| public class LocalService : Service | ||
| { | ||
| public virtual void Start() | ||
| { | ||
| } | ||
|
|
||
| public virtual void Stop() | ||
| { | ||
| } | ||
|
|
||
| public virtual void MessageReceive(Service service, object o) | ||
| { | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,36 @@ | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Service.Service | ||
| { | ||
| public class Service | ||
| { | ||
| public static LocalService GetService() | ||
| { | ||
| return Entity.GetEntity().GetLocalService(); | ||
| } | ||
|
|
||
| public virtual Entity NewEntity() | ||
| { | ||
| if (Entity.GetEntity() == null) | ||
| return null; | ||
|
|
||
| var localService = Entity.GetEntity().GetLocalService(); | ||
| if (localService == this) | ||
| return null; | ||
|
|
||
| var entity = localService.NewEntity(); | ||
| //entity.AddReceiver(this); | ||
| return entity; | ||
| } | ||
|
|
||
| public Service GetService(string name) | ||
| { | ||
| return null; | ||
| } | ||
| public List<Netronics.Template.Service.Service.Service> GetServices(string name) | ||
| { | ||
| //test | ||
| return null;// new RemoteService(); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,3 @@ | ||
| <?xml version="1.0"?> | ||
| <configuration> | ||
| <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration> |