denoを使ってローカルマシン上で動作するクライアントアプリを作ろうとしている。
ユーザの視界に入るのはインターフェースであるブラウザだけにして、裏で動作するdenoが見えないように運用するイメージで検討中。
denoのプロセスを終了させるためのボタンをブラウザ上に配置するサンプルが以下。
ユーザの視界に入るのはインターフェースであるブラウザだけにして、裏で動作するdenoが見えないように運用するイメージで検討中。
denoのプロセスを終了させるためのボタンをブラウザ上に配置するサンプルが以下。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// --allow-run --allow-net --allow-read | |
import { listenAndServe } from "https://deno.land/std/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); | |
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") { | |
if(msg == 'shutdown'){ return Deno.exit() } | |
dispatch(`[${id}] > ${msg}`); | |
} else if (isWebSocketCloseEvent(msg)) { | |
clients.delete(id); | |
dispatch(`[${id}]さんが退室しました`); | |
break; | |
} | |
} | |
} | |
function dispatch(msg: string): void { | |
console.log('dispatch:'+msg) | |
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) | |
console.log('send err. key['+key+'] msg['+msg+']') | |
} | |
} | |
} | |
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]}) | |
} | |
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 | |
}); | |
} | |
async function リクエスト処理(request: any){ | |
if(request.method != 'GET'){return} | |
アドレス毎(request) | |
} | |
for(let port=49152; port<=65535 ;port++){ | |
try{ | |
const server = listenAndServe({ port: port }, async (req)=> { リクエスト処理(req) }); | |
console.log(`HTTP webserver running. Access it at: http://localhost:` + port + `/`); | |
} | |
catch(e){continue} | |
ブラウザ起動(port) | |
break | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="ja"> | |
<head> | |
<meta charset="UTF-8" /> | |
<title>wawawa--</title> | |
</head> | |
<body> | |
<p class=greenText>wowowo--</p> | |
<button id=btn0>deno shutdown</button> | |
<button id=btn1>connect</button> | |
<ul id="timeline"></ul> | |
</body> | |
<script> | |
let ws | |
function ws接続(){ | |
if(ws){ ws.close() } | |
ws = new WebSocket(`ws://${location.host}/ws`) | |
ws.addEventListener("open", () => { | |
timeline.appendChild(messageDom('open')); | |
}); | |
ws.addEventListener("message", ({data}) => { | |
timeline.appendChild(messageDom(data)); | |
}); | |
ws.addEventListener("close", () => { | |
timeline.appendChild(messageDom('close')); | |
}); | |
} | |
btn1.onclick = ws接続 | |
btn0.onclick = function(){ | |
ws.send('shutdown') | |
} | |
function messageDom(msg) { | |
const li = document.createElement("li"); | |
li.className = "message"; | |
li.innerText = msg; | |
return li; | |
} | |
ws接続() | |
</script> | |
</html> |
実行直後のcmd
私のPCではIE11がデフォルトブラウザなのでIE11が起動するが、webSocketに対応していないのでボタンを押しても何も起きない。
edgeで開いた場合は以下の表示になる。
edgeで開いた後のcmd。webSocketが動作している。
edgeで「shutdown」ボタンを押した後の状態。
edgeで「shutdown」ボタンを押した後のcmd。
以下のページを参考にさせて頂きました。
Denoの標準ライブラリでチャットアプリを作ってみました🦕
WebSocketについて調べてみた。
私のPCではIE11がデフォルトブラウザなのでIE11が起動するが、webSocketに対応していないのでボタンを押しても何も起きない。
edgeで開いた場合は以下の表示になる。
edgeで開いた後のcmd。webSocketが動作している。
edgeで「shutdown」ボタンを押した後の状態。
edgeで「shutdown」ボタンを押した後のcmd。
以下のページを参考にさせて頂きました。
Denoの標準ライブラリでチャットアプリを作ってみました🦕
WebSocketについて調べてみた。
0 件のコメント:
コメントを投稿