Open7
統合版マイクラ向けのライブラリづくりメモ
MinecraftConnectionBE をつくりますかぁ~
基本となる考え方はこれ。
もうちょっと使いやすくしたい。
必要そうなもの
結構あるなぁ
- WebSocket でサーバを立てる
- 接続処理
- レスポンス処理
- エラー処理
- 切断処理
- JSONシリアライザ
- プロパティ
多分ライブラリ依存しないほうがいいと思うので、なるべく .NET STL で実装したい。多分基本形になるのがこれ
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
using (var ws = new ClientWebSocket())
{
Uri serverUri = new Uri("ws://localhost:8080");
await ws.ConnectAsync(serverUri, CancellationToken.None);
Console.WriteLine("connected");
while (ws.State == WebSocketState.Open)
{
byte[] buffer = new byte[1024];
WebSocketReceiveResult result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Text)
{
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
Console.WriteLine("Received message: " + message);
}
}
Console.ReadKey(true);
}
}
}
GPTに相談
using System;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:8080/");
listener.Start();
Console.WriteLine("Listening...");
while (true)
{
HttpListenerContext context = await listener.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
WebSocket webSocket = await context.AcceptWebSocketAsync(null);
Console.WriteLine("WebSocket connection established.");
CancellationTokenSource cts = new CancellationTokenSource();
// Ctrl+Cを押下するまで、コマンドの入力を待機する
Task sendTask = Task.Run(async () =>
{
while (!cts.Token.IsCancellationRequested)
{
Console.Write("Enter command: ");
string command = Console.ReadLine();
if (!string.IsNullOrEmpty(command))
{
byte[] buffer = Encoding.UTF8.GetBytes(command);
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
Console.WriteLine($"Sent message: {command}");
}
}
});
// Ctrl+Cを押下すると、CancellationTokenSourceをキャンセルする
Console.CancelKeyPress += (sender, eArgs) =>
{
eArgs.Cancel = true;
cts.Cancel();
};
byte[] receiveBuffer = new byte[1024];
// クライアントからのメッセージを受信し続ける
while (webSocket.State == WebSocketState.Open)
{
WebSocketReceiveResult receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
if (receiveResult.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
else
{
string command = Encoding.UTF8.GetString(receiveBuffer, 0, receiveResult.Count);
Console.WriteLine($"Received command: {command}");
}
}
await sendTask;
webSocket.Dispose();
Console.WriteLine("WebSocket connection closed.");
}
else
{
context.Response.StatusCode = 400;
context.Response.Close();
}
}
}
}
第2案のメモ書き
public class MCWebSocket
{
protected string Url { get; }
protected ushort Port { get; }
private WebSocket _ws;
protected MCWebSocket(string url, ushort port)
{
Url = url;
Port = port;
}
protected async Task WebServerStart()
{
var listener = new HttpListener();
listener.Prefixes.Add($"http://{Url}:{Port}/");
listener.Start();
#if DEBUG
Console.WriteLine("server started.");
#endif
while (true)
{
var context = await listener.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
_ws = (await context.AcceptWebSocketAsync(null)).WebSocket;
CancellationTokenSource cts = new CancellationTokenSource();
Task sendTask = Task.Run(async () =>
{
while (!cts.Token.IsCancellationRequested)
{
string command = Console.ReadLine();
if (!string.IsNullOrEmpty(command))
{
var buffer = Encoding.UTF8.GetBytes(command);
await _ws.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
});
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
var receiveBuffer = new byte[1024];
while (_ws.State == WebSocketState.Open)
{
var receiveResult = await _ws.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
if (receiveResult.MessageType == WebSocketMessageType.Close)
{
await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
else
{
var result = Encoding.UTF8.GetString(receiveBuffer, 0, receiveResult.Count);
Console.WriteLine(result);
}
}
await sendTask;
_ws.Dispose();
//await HandleWebSocketAsync(_ws);
}
else
{
context.Response.StatusCode = 400;
context.Response.Close();
}
}
}
protected async Task HandleWebSocketAsync(WebSocket ws)
{
var buffer = new byte[1024];
while (ws.State == WebSocketState.Open)
{
var result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
else
{
var message = Encoding.UTF8.GetString(buffer);
#if DEBUG
Console.WriteLine(message);
#endif
var responseBuffer = Encoding.UTF8.GetBytes(message);
await ws.SendAsync(new ArraySegment<byte>(responseBuffer), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}
protected async Task<string> SendCommandAsync(string command)
{
var receiveBuffer = new byte[1024];
var sendBuffer = Encoding.UTF8.GetBytes(command);
await _ws.SendAsync(new ArraySegment<byte>(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None);
#if DEBUG
Console.WriteLine(command);
#endif
var response = await _ws.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
var result = Encoding.UTF8.GetString(receiveBuffer, 0, response.Count);
#if DEBUG
Console.WriteLine(result);
#endif
return result;
}
}
一旦、WebSocketSharp に頼ることにした。多分1から作ると時間がかかりそうなのと、MinecraftConnectionのように最初はライブラリ依存しつつも早く仕上げる方向性でやってみるか。
OpenAI APIと組み合わせてできた