2021年5月30日日曜日

denoとブラウザの間をwebSocketで接続するだけ

ブラウザからローカルファイルを読み書きしたり各種コマンドを実行できるようにするためにブラウザとdenoの間で通信できるようにしたいです。
まずは接続するだけのソースが以下。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>wawawa--</title>
<link rel="stylesheet" type="text/css" href="./css.css">
</head>
<body>
<p class=greenText>wowowo--</p>
</body>
<script>
let ws
function ws接続(){
if(ws){ ws.close() }
ws = new WebSocket(`ws://${location.host}/ws`)
}
ws接続()
</script>
</html>
view raw index.html hosted with ❤ by GitHub
// --allow-run --allow-net --allow-read
import { serve } from "https://deno.land/std@0.86.0/http/server.ts";
import * as path from "https://deno.land/std@0.97.0/path/mod.ts"; // pathResolver
import {
acceptWebSocket,
acceptable,
WebSocket,
isWebSocketCloseEvent,
} from "https://deno.land/std/ws/mod.ts";
function pathResolver(meta: ImportMeta): (p: string) => string {
return (p) => path.fromFileUrl(new URL(p, meta.url))
}
const resolve = pathResolver(import.meta);
async function サーバ起動後(サーバ: any){
for await (const request of サーバ) {
if(request.method != 'GET'){return}
アドレス毎(request)
}
}
async function アドレス毎(request: any){
console.log('url:[' + request.url + ']')
let url = request.url
if(url=='/ws'){return webSocket接続(request)}
if(url=='/'){ url = './index.html' }
if(url.indexOf('/')==0){ url = '.' + url }
url = resolve(url)
const ファイルの有無 = await fileExists(url)
if(!ファイルの有無){
return request.respond({ status: 404 })
}
const file = await Deno.open(url);
request.respond({
status: 200,
headers: new Headers({"content-type": 拡張子2contentType(url)}),
body: file
});
}
function webSocket接続(request: any):void{
console.log('webSocket接続')
if(!acceptable(request)){return console.log('webSocket接続 not acceptable')}
acceptWebSocket({
conn: request.conn,
bufReader: request.r,
bufWriter: request.w,
headers: request.headers,
}).then(wsHandler);
}
const clients = new Map<number, WebSocket>();
let clientId = 0;
async function wsHandler(ws: WebSocket): Promise<void> {
const id = ++clientId;
clients.set(id, ws);
dispatch(`[${id}]さんが入室しました`);
for await (const msg of ws) {
if (typeof msg === "string") {
dispatch(`[${id}] > ${msg}`);
} else if (isWebSocketCloseEvent(msg)) {
clients.delete(id);
dispatch(`[${id}]さんが退室しました`);
break;
}
}
}
function dispatch(msg: string): void {
for (const key of clients.keys()) {
let client = clients.get(key)
if(client==undefined){
clients.delete(key)
continue
}
try{ client.send(msg) }
catch(e){ clients.delete(key) } // メッセージの送信に失敗した相手は切断済みと判断する。
}
}
function 拡張子2contentType(url: string):string{
if(url.match(/\.htm(l?)$/)){return 'text/html'}
if(url.match(/\.css$/)){return 'text/css'}
return ''
}
async function fileExists(filePath: string): Promise<boolean> {
try {
await Deno.lstat(filePath);
return true;
} catch (err) {
if (err instanceof Deno.errors.NotFound) {
return false;
}
throw err;
}
}
function ブラウザ起動(port: number){
Deno.run({cmd:['cmd', '/C start http://localhost:'+port]})
}
for(let port=49152; port<=65535 ;port++){
try{
const server = serve({ hostname: "0.0.0.0", port: port });
console.log(`HTTP webserver running. Access it at: http://localhost:` + port + `/`);
サーバ起動後(server)
}
catch(e){continue}
ブラウザ起動(port)
break
}
view raw webSocket.ts hosted with ❤ by GitHub
実行結果
webSocketに対応していないブラウザで開いた場合は上図のようになる。



edgeで開くと以下のようになる。


以下のページを参考にさせて頂きました。
Denoの標準ライブラリでチャットアプリを作ってみました🦕
WebSocketについて調べてみた。

0 件のコメント:

コメントを投稿