System.Net.PeerToPeer.Collaborationの実践

TechCollab2007-04-08


VirtualPCイメージでのOrcas環境だとなぜかC++のプロジェクトしか作成できなかったりしたので、ちょっと邪道にSystem.Net.dllを拝借して実環境のVistaで実装してみました。まあ、APIマニュアルもないのでClass構成を見つつ直感的に作ったものなのであっているのかはわかりませんが。。

とりあえず、People Near MeネットワークへのObject公開、各種イベント処理の実装をやってみたたけです。ご参考まで(Objectのイベントまわりは不十分なのはご勘弁ください)。


Window1.xaml.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using System.Net.PeerToPeer.Collaboration;  //People Near Me (Orcas 3.5)


namespace PNM_WPF_000
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>

    public partial class Window1 : System.Windows.Window
    {
        const string __GUID_OBJECT = "11111111-2222-3333-4444-555555555555";
        Dictionary<string, Ellipse> m_PeerFigures = new Dictionary<string, Ellipse>();
        Dictionary<string, string> m_PeerObjs = new Dictionary<string, string>();

        public Window1()
        {
            InitializeComponent();

            // People Near Meネットワークへの参加
            PeerCollaboration.SignIn(PeerScope.All);
            
            // Objectの登録
            RegistObj();

            //初期状態としてまわりにいるPeerをリストアップ
            ListupPeopleNearMe();
            
            //Peer状態変化にともなるイベントコールバック
            //PeerCollaboration.Local*Changed += new EventHandler<ObjectChangedEventArgs>(PeerCollaboration_LocalObjectChanged);
            PeerNearMe.PeerNearMeChanged += new EventHandler<PeerNearMeChangedEventArgs>(PeerNearMe_PeerNearMeChanged);
        }

        /// <summary>
        /// 近隣Peerのリストアップ
        /// </summary>
        private void ListupPeopleNearMe()
        {            
            PeerNearMeCollection pnms = PeerCollaboration.GetPeersNearMe();
            
            foreach (PeerNearMe pnm in pnms)
            {
                pnm.RefreshData();
                foreach (PeerObject obj in pnm.GetObjects(new Guid(__GUID_OBJECT)))
                {
                    string szObj = Encoding.Unicode.GetString(obj.Data);
                    obj.ObjectChanged += new EventHandler<ObjectChangedEventArgs>(PeerCollaboration_RemoteObjectChanged);
                    AddPeer(pnm.Nickname, szObj);
                }
            }
        }

        /// <summary>
        /// Peer(Object)の追加
        /// </summary>
        /// <param name="szNickName"></param>
        /// <param name="szObj"></param>
        private void AddPeer(string szNickName, string szObj)
        {
            Ellipse peerFigure = new Ellipse();
            peerFigure.ToolTip = "[NickName]: " + szNickName + "\n" + "[Object]: " + szObj;
            peerFigure.Fill = Brushes.Blue;
            peerFigure.Stroke = Brushes.Black;
            peerFigure.StrokeThickness = 2.5;
            Random ran = new Random(DateTime.Now.Millisecond);
            double radius = 180 * ran.NextDouble();
            peerFigure.Width = peerFigure.Height = radius;

            Canvas.SetLeft(peerFigure, (PeerCanvas.Width - radius) * ran.NextDouble());
            Canvas.SetTop(peerFigure, (PeerCanvas.Height - radius) * ran.NextDouble());

            PeerCanvas.Children.Add(peerFigure);
            m_PeerFigures.Add(szNickName, peerFigure);
            m_PeerObjs.Add(szNickName, szObj);
        }

        /// <summary>
        /// Peer(Object)の削除
        /// </summary>
        /// <param name="szNickName"></param>
        /// <param name="szObj"></param>
        private void DelPeer(string szNickName, string szObj)
        {
            Ellipse fig = m_PeerFigures[szNickName];
            PeerCanvas.Children.Remove(fig);
            m_PeerFigures.Remove(szNickName);
            m_PeerObjs.Remove(szNickName);
        }

        /// <summary>
        /// Peer(Object)の更新
        /// </summary>
        /// <param name="szNickName"></param>
        /// <param name="szObj"></param>
        private void UpdatePeer(string szNickName, string szObj)
        {
            Ellipse fig = m_PeerFigures[szNickName];
            fig.ToolTip = szObj;
            m_PeerObjs[szNickName] = szObj;
        }

        /// <summary>
        /// Peer Near Meネットワークに公開するオブジェクトを公開
        /// </summary>
        private void RegistObj()
        {
            PeerObject obj = new PeerObject(new Guid(__GUID_OBJECT), Encoding.Unicode.GetBytes(ObjectTextBox.Text), PeerScope.All);
            PeerCollaboration.SetObject(obj);
        }

        /// <summary>
        /// Publishボタンのコールバック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PublishButton_ButtonClicked(object sender, RoutedEventArgs e)
        {
            RegistObj();
        }

        /// <summary>
        /// Object状態変化のコールバック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PeerCollaboration_RemoteObjectChanged(object sender, ObjectChangedEventArgs e)
        {
            PeerObject obj = e.PeerObject;
            string szObj = Encoding.Unicode.GetString(obj.Data);

            PeerEndPoint endpoint = e.PeerEndPoint;
            string szNickName = endpoint.Name;

            switch (e.PeerChangeType)
            {                
                case PeerChangeType.Added:
                    AddPeer(szNickName, szObj);
                    break;
                case PeerChangeType.Deleted:
                    DelPeer(szNickName, szObj);
                    break;
                case PeerChangeType.Updated:
                    UpdatePeer(szNickName, szObj);
                    break;
                default:
                    break;
            }
        }


        /// <summary>
        /// People Near Me状態変化のコールバック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PeerNearMe_PeerNearMeChanged(object sender, PeerNearMeChangedEventArgs e)
        {
            // Objectの方で一括して管理するため特に何もせず
            switch (e.PeerChangeType)
            {
                case PeerChangeType.Added:
                    break;
                case PeerChangeType.Deleted:
                    break;
                case PeerChangeType.Updated:
                    break;
                default:
                    break;
            }
        }
       
    }
}

Window1.xaml

<Window x:Class="PNM_WPF_000.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="PNM_WPF_000" Height="500" Width="700"
    Background="#FFFFFFFF"
    >
	<Canvas x:Name="MainCanvas" Width="700" Height="500" Canvas.Left="0" Canvas.Top="0">
		<Canvas x:Name="PeerCanvas" Width="500" Height="500" Canvas.Left="0" Canvas.Top="0">
			<TextBlock Width="224" Height="25.75" Canvas.Left="8.75" Canvas.Top="6.25" FontSize="18" FontWeight="Bold" Text="Peer Status" TextWrapping="Wrap"/>
		</Canvas>
		<Canvas x:Name="PublishCanvas" Width="200" Height="500" Canvas.Left="500" Canvas.Top="0" Background="#FF85A5D2" TextElement.Foreground="#FF000000">
			<TextBlock Width="188" Height="33.75" Canvas.Left="8.75" Canvas.Top="6.25" FontWeight="Bold" TextWrapping="Wrap">
				<Run FontSize="17" Language="ja-jp">Object Publish</Run>
			</TextBlock>
			<TextBox x:Name="ObjectTextBox" Width="160" Height="280" FontSize="14" Canvas.Left="13.75" Canvas.Top="77.75" Text="Objectは指定されていません。" TextWrapping="Wrap"/>
			<Button x:Name="PublishButton" Width="77.127" FontSize="14" Content="Publish!" Canvas.Left="54.123" Canvas.Top="376" Click="PublishButton_ButtonClicked"/>
		</Canvas>
	</Canvas>
</Window>

。。。長っ!スクロールにすればよかったかな。。。


RSS Collaboratorもこんなことを内部でやってます。Mike TaultyさんのBlogでもPeople Near MeやWCFでのPeerChannelの話が書いてありますのでご参考に。
http://d.hatena.ne.jp/TechCollab/20070318
http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2006/12/29/9056.aspx