2017年3月3日金曜日

ネゴシエーション式ファイルロック(成功するまで待機)

昨日のサンプルはロック開始ボタンを押した瞬間だけロックを1回トライするものでした。
本日のサンプルは、ロックが成功するまで適当に待ち時間を挟みながら繰り返しトライして、ロックできたら編集を実行します。




以下ソース
<html>
<title>lock</title>
<body style="text-align:center;overflow:hidden">
<input id=inp style="width:100%;text-align:center">
<button id=btnL>load</button>
<button id=btnI>init</button>
<table border=1 style="width:100%;">
<tr><td width=1>A</td><td><input id=inpA style="width:100%"></td></tr>
<tr><td width=1>B</td><td><input id=inpB style="width:100%"></td></tr>
<tr><td width=1>C</td><td><input id=inpC style="width:100%"></td></tr>
</table>
</body>
<script>
resizeTo(200,200)
fso=function(){
var fs=new ActiveXObject('Scripting.FileSystemObject')
return {
AXO:fs,
gsf2:fs.GetSpecialFolder(2), // Z:\TEMP
Read:function(path, swCreate, swUnicode){
if(!fs.FileExists(path)){return}
with(fs.OpenTextFile(path, 1, swCreate, swUnicode)){ var str=AtEndOfStream ? '' : ReadAll(); Close() }
return str
},
Write:function(path,str,swUnicode,sw上書きしない){ with(fs.CreateTextFile(path, !sw上書きしない, swUnicode)){ Write(str); Close() } },
Lock:function(path){
var pathL=path+'.lock', ws, wsn=new ActiveXObject('WScript.Network')
try{
ws=fs.CreateTextFile(pathL)
ws.Write(wsn.computerName+'\r\n'+wsn.userName)
return {Close:function(){ ws.Close(); fs.DeleteFile(pathL) }}
}
catch(e){
return this.Read(pathL)
}
}
}
}()
inp.value = fso.gsf2+'\\lockTest.txt'
onbeforeunload=function(){ fso.AXO.FileExists(inp.value) && fso.AXO.DeleteFile(inp.value) }
obj = null
btnL.onclick=function(){
var path=inp.value, o
if(!fso.AXO.FileExists(path)){return alert('ファイルがありません')}
try{ eval('o = '+fso.Read(path)) }
catch(e){ return alert('ファイルが破損しています') }
obj = o
inpA.value = o.A
inpB.value = o.B
inpC.value = o.C
}
btnI.onclick=function(){
wsf.negoWrite(inp.value, function(path){ Write(path, "{A:'', B:'', C:''}") })
}
onload=function(){
btnI.onclick()
}
inpA.onchange=inpB.onchange=inpC.onchange=function(){
wsf.negoWrite(inp.value, (''+function(path){
eval('o = '+Read(path))
o.prop = 'VVV'
Write(path, "{A:'"+o.A.replace(/'/g,"\'")+"', B:'"+o.B.replace(/'/g,"\'")+"', C:'"+o.C.replace(/'/g,"\'")+"'}")
}).replace(/prop/,this.id.charAt(3)).replace(/VVV/,this.value.replace(/'/g,"\'")))
}
wsf=function(){
var pathWSF=fso.gsf2+'\\lock.wsf'
fso.Write(pathWSF, (''+function(){/*
<-job>
<-script>
arg = WScript.Arguments
path = arg(0)
pathF = arg(1)
pathL = path+'.lock'
AXO = function(name){return new ActiveXObject(name)}
fs = AXO('Scripting.FileSystemObject')
wsn = AXO('WScript.Network')
Read = function(path){with(fs.OpenTextFile(path)){ var str=AtEndOfStream ? '' : ReadAll(); Close() } return str}
Write= function(path,str){ with(fs.CreateTextFile(path)){ Write(str); Close() } },
eval('f = '+Read(pathF))
while(true){
try{
lock = fs.CreateTextFile(pathL)
lock.Write(wsn.computerName+'\r\n'+wsn.userName)
break
}
catch(e){ WScript.Sleep(1000 * 10 * Math.random()) } // 待ち時間が一定だと永遠にお見合い状態になってしまうので、ばらけさせる。
}
f(path)
// このスクリプトの動作を分かり易くするための待機時間。実際は不要。
WScript.Sleep(5000)
lock.Close()
try{
fs.DeleteFile(pathL)
fs.DeleteFile(pathF)
}catch(e){}
<-/script>
<-/job>
*/}).split('/*')[1].split('*/')[0].replace(/<-/g,'<'))
var shell=new ActiveXObject('WScript.Shell')
var pathDQ=function(path){return 0<path.indexOf(' ') ? ('"'+path+'"') : path }
return {
negoWrite:function(path, fun){
var pathF=fso.gsf2+'\\fun'+(new Date()).getTime()+'.js'
fso.Write(pathF, fun)
shell.run('cmd /C cscript '+pathDQ(pathWSF)+' '+pathDQ(path)+' '+pathDQ(pathF), 0)
}
}
}()
</script>
</html>



実行画面


inputエリア内に文字を入力して、


inputエリアからフォーカスを移動しonchangeイベントを発生させるとロックを繰り返しトライするためのwsfファイルが作成されます。


プログラムを一つだけ起動している場合、ファイルへのアクセスが競合することはないのでwsfファイルはすぐにロック成功して自身を削除しますが、プログラムを複数個起動して数秒以内にそれぞれのinputボックスでonchangeイベントを発生させると



onchangeイベントを発生させた数に応じて一時的なスクリプトファイルが作成されて



ロックが成功して処理終了したものから順次削除されていき、最終的には対象のファイルの中身は以下のようになります。


0 件のコメント:

コメントを投稿