File sharing with RTMFP
RTMFPを使用した、ファイル共有プログラムです。
データの受け渡し部分はP2Pで行われますが、仕組み的にはBitTorrentに近く、送受信側ともに複数クライアントが参加出来ます。
(RTMFPのオブジェクトレプリケーションを使用)
受信側も、既に受信した部分のデータは、送信に協力することになります。
違法なファイルのやり取りはしないでください。
送信側の操作:
[Provide]ボタンを押して、送信したいファイルを選択してください。
テキストボックスに、ファイルのハッシュ値が表示されますので、受信する人に伝えてください。
受信側の操作:
テキストボックスに、受信するファイルのハッシュ値を入力して、[Receive]ボタンを押してください。
受信が完了すると、[Receive]ボタンが[Save]ボタンになり、ファイルを保存出来ます。
♥11 |
Line 196 |
Modified 2010-11-07 21:06:16 |
GPLv3 License
archived:2017-03-07 07:45:34
ActionScript3 source code
/**
* Copyright Fake ( http://wonderfl.net/user/Fake )
* GNU General Public License, v3 ( http://www.gnu.org/licenses/quick-guide-gplv3.html )
* Downloaded from: http://wonderfl.net/c/rCkr
*/
<?xml version="1.0" encoding="utf-8"?>
<!--
I provide this code as GPL;
ライセンスはGPLです。
-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="onInitApp()">
<mx:Button id="btnProvide" label="Provide" x="30" y="50" />
<mx:Button id="btnReceive" label="Receive" x="30" y="150" />
<mx:Script>
<![CDATA[
import flash.events.ProgressEvent;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.net.FileReference;
import flash.display.Sprite;
import flash.text.TextFieldAutoSize;
import flash.text.TextField;
import com.adobe.crypto.SHA1;
import flash.events.NetStatusEvent;
import flash.net.*;
private var debugout:TextField;
private var txtHash:TextField;
private var filename:String;
private var filesize:uint;
private var filehash:String;
private var chunknum:uint;
private var isProvide:Boolean;
private var flgary:Array;
private var filedata:ByteArray;
private var recnum:uint;
private var gs:GroupSpecifier;
private var nc:NetConnection;
private var group:NetGroup;
private var CHUNK_SIZE:uint = 65536;
private function onInitApp():void {
// init debugout
debugout = new TextField();
debugout.x = 250;
debugout.y = 50;
debugout.autoSize = TextFieldAutoSize.LEFT;
debugout.background = true;
debugout.border = true;
debugout.backgroundColor = 0x000000;
debugout.textColor = 0x0000FF;
//parent.addChild(debugout);
txtHash = new TextField();
txtHash.x = 30;
txtHash.y = 100;
txtHash.autoSize = TextFieldAutoSize.LEFT;
txtHash.background = true;
txtHash.border = true;
txtHash.backgroundColor = 0xFFFFFF;
txtHash.textColor = 0x000000;
txtHash.restrict = "a-f0-9";
txtHash.type = TextFieldType.INPUT;
parent.addChild(txtHash);
txtHash.text = "Paste a file hash to receive.";
filedata = new ByteArray();
btnProvide.addEventListener(MouseEvent.CLICK, onProvideClicked);
btnReceive.addEventListener(MouseEvent.CLICK, onReceiveClicked);
}
private function onProvideClicked(e:MouseEvent):void {
var file:FileReference = new FileReference();
file.addEventListener(Event.SELECT, function (e:Event):void {
filename = e.target.name;
txtHash.text = "now loading";
e.target.load();
});
file.addEventListener(ProgressEvent.PROGRESS, function (e:ProgressEvent):void {
txtHash.appendText(".");
});
file.addEventListener(Event.COMPLETE, onFileLoaded);
file.browse();
btnProvide.enabled = false;
btnReceive.enabled = false;
txtHash.type = TextFieldType.DYNAMIC;
}
private function onReceiveClicked(e:MouseEvent):void {
isProvide = false;
filehash = txtHash.text;
txtHash.type = TextFieldType.DYNAMIC;
btnProvide.enabled = false;
btnReceive.enabled = false;
e.target.removeEventListener(e.type, onReceiveClicked);
initRTMFP(filehash);
}
private function onSaveClicked(e:MouseEvent):void {
var file:FileReference = new FileReference();
file.save(filedata, filename);
}
private function initRTMFP(hash:String):void {
debugout.appendText(hash + "\n");
// init rtmfp group spec
gs = new GroupSpecifier("net.wonderfl.fake.p2p.fileshare.test:" + hash);
gs.postingEnabled = true;
gs.ipMulticastMemberUpdatesEnabled = true;
gs.multicastEnabled = true;
gs.objectReplicationEnabled = true;
gs.routingEnabled = true;
gs.serverChannelEnabled = true;
// init rtmfp connection
nc = new NetConnection();
nc.addEventListener(NetStatusEvent.NET_STATUS, procNetStatus);
nc.connect("rtmfp://p2p.rtmfp.net/445d9931dfac67103408ae5f-ad98e28e2386/");
}
private function onFileLoaded(e:Event):void {
filehash = SHA1.hashBytes(e.target.data);
txtHash.text = filehash;
filesize = e.target.size;
isProvide = true;
filedata.writeBytes(e.target.data)
initRTMFP(filehash);
}
private function initFileSharing():void {
chunknum = Math.ceil(filesize / CHUNK_SIZE);
group.addHaveObjects(0, chunknum);
// init flag array
flgary = new Array();
for (var i:int = 0; i < chunknum; ++i) {
flgary.push(true);
}
}
private function initFileReceiving():void {
group.addWantObjects(0, 0);
recnum = 0;
}
private function procNetStatus(e:NetStatusEvent):void {
debugout.appendText(e.info.code + "\n");
switch (e.info.code) {
case "NetConnection.Connect.Success":
try {
group = new NetGroup(nc, gs.groupspecWithAuthorizations());
group.addEventListener(NetStatusEvent.NET_STATUS, procNetStatus);
group.replicationStrategy = NetGroupReplicationStrategy.RAREST_FIRST;
} catch (e:Error) {
debugout.appendText(e.toString() + "\n");
}
break;
case "NetGroup.Connect.Success":
isProvide ? initFileSharing() : initFileReceiving();
break;
case "NetGroup.Neighbor.Connect":
break;
case "NetGroup.Posting.Notify":
break;
case "NetGroup.Replication.Request":
if (e.info.index == 0) {
group.writeRequestedObject(e.info.requestID, {
filename: filename,
filesize: filesize,
filehash: filehash,
chunknum: chunknum
});
} else if (e.info.index <= chunknum) {
var b:ByteArray = new ByteArray();
filedata.position = (e.info.index - 1) * CHUNK_SIZE;
var rsize:uint = filesize - filedata.position;
if (rsize > CHUNK_SIZE) {
rsize = CHUNK_SIZE;
}
filedata.readBytes(b, 0, rsize);
group.writeRequestedObject(e.info.requestID, {
data: b
});
} else {
// indexが範囲外
group.denyRequestedObject(e.info.requestID);
}
break;
case "NetGroup.Replication.Fetch.Result":
var obj:Object = e.info.object;
if (e.info.index == 0) {
filename = obj.filename;
filesize = obj.filesize;
filehash = obj.filehash;
chunknum = obj.chunknum;
group.addWantObjects(1, chunknum);
// init flag array
flgary = new Array();
for (var i:int = 0; i < chunknum; ++i) {
flgary.push(false);
}
} else if (e.info.index <= chunknum) {
debugout.appendText(e.info.index.toString + "\n");
filedata.position = (e.info.index - 1) * CHUNK_SIZE;
filedata.writeBytes(obj.data);
flgary[e.info.index-1] = true;
group.addHaveObjects(e.info.index, e.info.index);
++recnum;
} else {
// indexが範囲外
}
txtHash.text = recnum.toString() + "/" + chunknum.toString();
if (flgary.indexOf(false) === -1) {
// 全ピースを受け取り完了
btnReceive.enabled = true;
btnReceive.label = "Save";
btnReceive.addEventListener(MouseEvent.CLICK, onSaveClicked);
}
break;
}
}
]]>
</mx:Script>
</mx:Application>