/// <summary> /// Create a new download queue item based on a url. Takes URLs in the format fap://NodeID/path/to/file /// </summary> /// <param name="url"></param> public void AddDownloadURL(string url) { string parentDir = Utility.DecodeURL(url); //Strip protocol if (parentDir.StartsWith("fap://", StringComparison.InvariantCultureIgnoreCase)) parentDir = parentDir.Substring(6); int index = parentDir.LastIndexOf('/'); if (index == -1) { LogManager.GetLogger("faplog").Error("Unable to add download as an invalid url as passed!"); } else { string fileName = parentDir.Substring(index + 1); parentDir = parentDir.Substring(0, index); string nodeId = parentDir.Substring(0, parentDir.IndexOf('/')); parentDir = parentDir.Substring(nodeId.Length + 1); Node node = network.Nodes.Where(n => n.ID == nodeId).FirstOrDefault(); if (null == node) { //Node not found LogManager.GetLogger("faplog").Error("Unable to add download as node {0} was not found!", nodeId); } else { //Node found - browse to get info var verb = new BrowseVerb(null); verb.NoCache = false; verb.Path = parentDir; var client = new Client(LocalNode); if (client.Execute(verb, node)) { BrowsingFile remoteFile = verb.Results.Where(f => f.Name == fileName).FirstOrDefault(); if (null != remoteFile) { downloadQueue.List.Add(new DownloadRequest { Added = DateTime.Now, FullPath = parentDir + "/" + remoteFile.Name, IsFolder = remoteFile.IsFolder, Size = remoteFile.Size, LocalPath = null, State = DownloadRequestState.None, ClientID = node.ID, Nickname = node.Nickname }); } else { LogManager.GetLogger("faplog").Error( "Unable to add download as {0} was not found on the remote server!", fileName); } } else { LogManager.GetLogger("faplog").Error("Unable to add download as node {0} was not accessible!", nodeId); } } } }
private void process(object o) { try { while (true) { DownloadRequest currentItem = null; bool QueueEmpty = false; lock (sync) QueueEmpty = queue.Count == 0; if (QueueEmpty && null != OnWorkerFinished) OnWorkerFinished(this, EventArgs.Empty); lock (sync) { if (queue.Count > 0) currentItem = queue.Dequeue(); if (null == currentItem) { isComplete = true; return; } } currentItem.State = DownloadRequestState.Downloading; if (currentItem.IsFolder) { length = 0; position = 0; status = "Downloading folder info for " + currentItem.FullPath; //Item is a folder - Just get the folder items and add them to the queue. var verb = new BrowseVerb(null); verb.Path = currentItem.FullPath; //Always get the latest info. verb.NoCache = true; var client = new Client(null); if (client.Execute(verb, remoteNode)) { currentItem.State = DownloadRequestState.Downloaded; var newItems = new List<DownloadRequest>(); foreach (BrowsingFile item in verb.Results) { newItems.Add(new DownloadRequest { Added = DateTime.Now, ClientID = remoteNode.ID, FullPath = currentItem.FullPath + "/" + item.Name, IsFolder = item.IsFolder, LocalPath = currentItem.LocalPath + "\\" + currentItem.FileName, NextTryTime = 0, Nickname = remoteNode.Nickname, Size = item.Size, State = DownloadRequestState.None }); } model.DownloadQueue.List.AddRange(newItems); } else { currentItem.State = DownloadRequestState.Error; currentItem.NextTryTime = Environment.TickCount + Model.DOWNLOAD_RETRY_TIME; } } else { MemoryBuffer buffer = bufferService.GetBuffer(); buffer.SetDataLocation(0, buffer.Data.Length); //Item is a file - download it try { length = currentItem.Size; position = 0; status = currentItem.Nickname + " - " + currentItem.FileName + " - Connecting.."; currentItem.State = DownloadRequestState.Downloading; string mainPath = string.Empty; string mainFolder = string.Empty; string incompletePath = string.Empty; ; string incompleteFolder = string.Empty; //Build paths var mainsb = new StringBuilder(); mainsb.Append(model.DownloadFolder); if (!string.IsNullOrEmpty(currentItem.LocalPath)) { mainsb.Append("\\"); mainsb.Append(currentItem.LocalPath); } mainFolder = mainsb.ToString(); mainsb.Append("\\"); mainsb.Append(currentItem.FileName); mainPath = mainsb.ToString(); var incompletesb = new StringBuilder(); incompletesb.Append(model.IncompleteFolder); if (!string.IsNullOrEmpty(currentItem.LocalPath)) { incompletesb.Append("\\"); incompletesb.Append(currentItem.LocalPath); } incompleteFolder = incompletesb.ToString(); incompletesb.Append("\\"); incompletesb.Append(currentItem.FileName); incompletePath = incompletesb.ToString(); FileStream fileStream = null; //Check to see if the file already exists. if (File.Exists(mainPath)) { //File exists in the download directory. fileStream = File.Open(mainPath, FileMode.Open, FileAccess.Write, FileShare.None); incompletePath = mainPath; } else { if (!Directory.Exists(incompleteFolder)) Directory.CreateDirectory(incompleteFolder); //Else resume or just create fileStream = File.Open(incompletePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); } var req = (HttpWebRequest) WebRequest.Create(Multiplexor.Encode(getDownloadUrl(), "GET", currentItem.FullPath)); req.UserAgent = Model.AppVersion; req.Headers.Add("FAP-SOURCE", model.LocalNode.ID); // req.Timeout = 300000; // req.ReadWriteTimeout = 3000000; //If we are resuming then add range long resumePoint = 0; if (fileStream.Length != 0) { //Yes Micrsoft if you read this... OH WHY IS ADDRANGE ONLY AN INT?? We live in an age where we might actually download more than 2gb //req.AddRange(fileStream.Length); //Hack MethodInfo method = typeof (WebHeaderCollection).GetMethod("AddWithoutValidate", BindingFlags.Instance | BindingFlags.NonPublic); string key = "Range"; string val = string.Format("bytes={0}", fileStream.Length); method.Invoke(req.Headers, new object[] {key, val}); position = fileStream.Length; resumePoint = fileStream.Length; //Seek to the end of the file fileStream.Seek(fileStream.Length, SeekOrigin.Begin); } var resp = (HttpWebResponse) req.GetResponse(); if (resp.StatusCode == HttpStatusCode.OK) { using (Stream responseStream = resp.GetResponseStream()) { var tokenizer = new StreamTokenizer(Encoding.ASCII, "|"); var utilisedBuffers = new List<MemoryBuffer>(); try { bool streamIncomplete = true; while (streamIncomplete) { MemoryBuffer tokenBuffer = bufferService.GetSmallBuffer(); //utilisedBuffers.Add(tokenBuffer); //Receive data tokenBuffer.SetDataLocation(0, responseStream.Read(tokenBuffer.Data, 0, tokenBuffer.DataSize)); tokenizer.ReceiveData(tokenBuffer); if (tokenizer.ContainsCommand()) { string data = tokenizer.GetCommand(); int queuePosition = int.Parse(data); if (queuePosition == 0) { if (tokenizer.Buffers.Count > 0) { LogManager.GetLogger("faplog").Warn( "Queue info overlaps with file data. File: {0}", currentItem.FileName); //Due to the way chunks are delivered we should never get here //Just incase write left over data foreach (MemoryBuffer buff in tokenizer.Buffers) fileStream.Write(buff.Data, 0, buff.DataSize); } status = currentItem.Nickname + " - " + currentItem.FileName + " - " + Utility.FormatBytes(currentItem.Size); DateTime start = DateTime.Now; while (true) { //Receive file int read = responseStream.Read(buffer.Data, 0, buffer.Data.Length); if (read == 0) { streamIncomplete = false; break; } else { fileStream.Write(buffer.Data, 0, read); position += read; netSpeed.PutData(read); } } //Add log of transfer double seconds = (DateTime.Now - start).TotalSeconds; var rxlog = new TransferLog(); rxlog.Added = currentItem.Added; rxlog.Completed = DateTime.Now; rxlog.Filename = currentItem.FileName; rxlog.Nickname = currentItem.Nickname; rxlog.Path = currentItem.FolderPath; rxlog.Size = currentItem.Size - resumePoint; if (0 != seconds) rxlog.Speed = (int) (rxlog.Size/seconds); model.CompletedDownloads.Add(rxlog); } else { //Queued status = currentItem.Nickname + " - " + currentItem.FileName + " - Queue position " + queuePosition; } } } } finally { foreach (MemoryBuffer buff in utilisedBuffers) bufferService.FreeBuffer(buff); tokenizer.Dispose(); } } } resp.Close(); model.DownloadQueue.List.Remove(currentItem); currentItem.State = DownloadRequestState.Downloaded; fileStream.Close(); fileStream.Dispose(); //Move from the incomplete folder. if (mainPath != incompletePath) { if (!Directory.Exists(mainFolder)) Directory.CreateDirectory(mainFolder); File.Move(incompletePath, mainPath); } status = currentItem.Nickname + " - Complete: " + currentItem.FileName; resp.Close(); } catch { currentItem.State = DownloadRequestState.Error; currentItem.NextTryTime = Environment.TickCount + Model.DOWNLOAD_RETRY_TIME; } finally { bufferService.FreeBuffer(buffer); } } } } catch { //Something went very wrong. Clear the queue and die. lock (sync) { isComplete = true; foreach (DownloadRequest v in queue) v.State = DownloadRequestState.None; queue.Clear(); } } }
private void SendMessageAsync(object ivm) { var vm = ivm as ConversationViewModel; if (null != vm && !string.IsNullOrEmpty(vm.CurrentChatMessage)) { string message = vm.CurrentChatMessage; var c = new Client(model.LocalNode); var verb = new ConversationVerb(); verb.Nickname = model.LocalNode.Nickname; verb.Message = message; verb.SourceID = model.LocalNode.ID; vm.CurrentChatMessage = string.Empty; if (!c.Execute(verb, vm.Conversation.OtherParty)) vm.Conversation.Messages.Add("The other party failed to receive your message, please try again."); } }
private void RunAsync(object o) { lock (sync) { requests++; } var node = o as Node; if (null != node) { var client = new Client(model.LocalNode); var verb = new CompareVerb(model); if (client.Execute(verb, node)) { if (!verb.Allowed) { verb.Node.Nickname = node.Nickname; verb.Node.Location = node.Location; verb.Node.Status = "Denied"; data.Add(verb.Node); } else { verb.Node.Nickname = node.Nickname; verb.Node.Location = node.Location; verb.Node.Status = "OK"; data.Add(verb.Node); } } else { verb.Node = new CompareNode(); verb.Node.Nickname = node.Nickname; verb.Node.Location = node.Location; verb.Node.Status = "Error"; data.Add(verb.Node); } } lock (sync) { requests--; viewModel.Status = "Status: Waiting for a response from " + requests + " peers.."; if (requests == 0) { viewModel.EnableRun = true; viewModel.Status = "Status: All Information recieved, click start to refresh info (Note clients will cache information for 5 minutes)."; } } }
protected override void OnStartup(StartupEventArgs e) { if(e.Args.Contains("WAIT")) Thread.Sleep(5000); SplashScreen appSplash = null; Fap.Foundation.SafeObservableStatic.Dispatcher = System.Windows.Application.Current.Dispatcher; SafeObservingCollectionManager.Start(); this.DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(App_DispatcherUnhandledException); FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); base.OnStartup(e); if (Compose()) { if (e.Args.Length == 1 && e.Args[0] == "WAIT") { //Delay the application starting up, used when restarting. Thread.Sleep(3000); } ApplicationCore core = container.Resolve<ApplicationCore>(); if (!core.CheckSingleInstance()) { //An instance of fap is already running. //If we got a download url then forward onto the runing instance of FAP if (e.Args.Length == 2 && e.Args[0] == "-url") { Model model = new Model(); model.Load(); Client client = new Client(model.LocalNode); AddDownload verb = new AddDownload(); verb.URL = e.Args[1]; if (client.Execute(verb, model.LocalNode)) { //Download sent successfully Shutdown(0); return; } else { //Unsuccessful - Notify user WPFMessageBox.Show("FAP", "Failed to add download via RPC!"); Shutdown(1); return; } } else { //Inform the user they cannot run multiple instances WPFMessageBox.Show("FAP", "An instance of FAP is already running"); Shutdown(1); return; } } string img = GetImage(); appSplash = new SplashScreen(img); appSplash.Show(true); if (core.Load(false)) { core.StartClient(); core.StartGUI(!(e.Args.Contains("STARTUP"))); //Was a url passed on startup? if (e.Args.Length == 2 && e.Args[0] == "-url") { core.AddDownloadUrlWhenConnected(e.Args[1]); } } else { Shutdown(1); } } else { Shutdown(1); } if (null != appSplash) appSplash.Close(TimeSpan.FromSeconds(0)); }
private void Process(object o) { try { while (running) { while (pendingRequests.Count > 0) { NetworkRequest req = pendingRequests[0]; pendingRequests.RemoveAt(0); destination.LastUpdate = Environment.TickCount; var c = new Client(source); if (!c.Execute(req, destination)) { //Error running = false; return; } } //Check for client time out if ((Environment.TickCount - destination.LastUpdate) > Model.UPLINK_TIMEOUT) { //We havent recently sent/recieved so went a noop so check we are still connected. var req = new NetworkRequest {Verb = "NOOP", SourceID = source.ID, AuthKey = destination.Secret}; var client = new Client(source); if (!client.Execute(req, destination, 4000)) { //Error running = false; return; } } //Wait until there is work to do or 5 seconds have elapsed workerEvent.WaitOne(5000); } } catch { } finally { if (null != OnDisconnect) OnDisconnect(this); } }
private void RunAsync(object o) { var param = o as AsyncSearchParam; if (null != param && null != param.Node) { var client = new Client(model.LocalNode); var verb = new SearchVerb(null); verb.SearchString = viewModel.SearchString; switch (viewModel.SizeSearchType) { case "Any Size": break; case "Less than": verb.SmallerThan = GetSearchSize(); break; case "Greater than": verb.LargerThan = GetSearchSize(); break; } switch (viewModel.ModifiedSearchType) { case "Any": break; case "Before": verb.ModifiedBefore = (DateTime) viewModel.ModifiedDate; break; case "After": verb.ModifiedAfter = (DateTime) viewModel.ModifiedDate; break; } if (client.Execute(verb, param.Node)) { if (null != verb.Results) { //Set name foreach (SearchResult result in verb.Results) { result.User = param.Node.Nickname; result.ClientID = param.Node.ID; } param.Results.AddRange(verb.Results); } } } lock (sync) { //If we still on the same search then update the UI. if (param.Results == currentResults) { outstandingrequests--; if (outstandingrequests < 1) { viewModel.UpperStatusMessage = "Search complete in " + (Environment.TickCount - startTime) + " ms"; viewModel.LowerStatusMessage = currentResults.Count + " results."; } else { viewModel.LowerStatusMessage = outstandingrequests + " peers remaining.."; } } } }
private void SendMessageAsync(object o) { try { if (model.Network.State == ConnectionState.Connected) { var client = new Client(model.LocalNode); if (!client.Execute((NetworkRequest) o, model.Network.Overlord)) { if (model.Network.State == ConnectionState.Connected) model.Network.State = ConnectionState.Disconnected; } } else { LogManager.GetLogger("faplog").Warn("Could not send message as you are not conencted"); } } catch (Exception e) { LogManager.GetLogger("faplog").ErrorException("Failed to send chat message", e); } }
/// <summary> /// Whilst connected to a network /// </summary> public void CheckModelChanges() { if (model.Network.State == ConnectionState.Connected) { UpdateVerb verb = null; lock (sync) { var data = new Dictionary<string, string>(); foreach (var entry in model.LocalNode.Data) { if (transmitted.IsKeySet(entry.Key)) { if (transmitted.GetData(entry.Key) != entry.Value) { data.Add(entry.Key, entry.Value); } } else { data.Add(entry.Key, entry.Value); } } //Data has changed, transmit the changes. if (data.Count > 0) { verb = new UpdateVerb(); var n = new Node(); n.ID = model.LocalNode.ID; foreach (var change in data) { n.SetData(change.Key, change.Value); transmitted.SetData(change.Key, change.Value); } verb.Nodes.Add(n); } } if (null != verb) { var c = new Client(model.LocalNode); if (!c.Execute(verb, model.Network.Overlord)) model.Network.State = ConnectionState.Disconnected; } } }
private bool Connect(Domain.Entities.Network net, DetectedNode n) { try { LogManager.GetLogger("faplog").Info("Client connecting to {0}", n.Address); net.State = ConnectionState.Connecting; var verb = new ConnectVerb(); verb.ClientType = ClientType.Client; verb.Address = model.LocalNode.Location; verb.Secret = IDService.CreateID(); var client = new Client(model.LocalNode); transmitted.Data.Clear(); foreach (var info in model.LocalNode.Data.ToList()) transmitted.SetData(info.Key, info.Value); net.Overlord = new Node(); net.Overlord.Location = n.Address; net.Overlord.Secret = verb.Secret; LogManager.GetLogger("faplog").Debug("Client using secret {0}", verb.Secret); if (client.Execute(verb, n.Address)) { net.State = ConnectionState.Connected; net.Overlord.ID = verb.OverlordID; LogManager.GetLogger("faplog").Info("Client connected"); return true; } else { net.Overlord = new Node(); } } catch { net.State = ConnectionState.Disconnected; } return false; }
private void ProcessLanConnection(object o) { mserver.SendMessage(WhoVerb.CreateRequest()); Domain.Entities.Network network = model.Network; network.PropertyChanged += network_PropertyChanged; while (run) { if (network.State != ConnectionState.Connected) { //Not connected so connect automatically.. //Regenerate local secret to stop any updates if we reconnecting.. network.Overlord = new Node(); network.Overlord.Secret = IDService.CreateID(); //Clear old peers network.Nodes.Clear(); //Build up a prioritised server list var availibleNodes = new List<DetectedNode>(); List<DetectedNode> detectedPeers = peerFinder.Peers.ToList(); //Prioritise a server we havent connected to already foreach (DetectedNode peer in detectedPeers) { if (attemptedPeers.Where(s => s.Node == peer).Count() == 0) availibleNodes.Add(peer); } foreach (LanPeer peer in attemptedPeers.OrderByDescending(x => x.LastConnectionTime)) { availibleNodes.Add(peer.Node); } while (network.State != ConnectionState.Connected && availibleNodes.Count > 0) { DetectedNode node = availibleNodes[0]; availibleNodes.RemoveAt(0); if (!Connect(network, node)) peerFinder.RemovePeer(node); } } if (network.State == ConnectionState.Connected) { CheckModelChanges(); //Check for network timeout if ((Environment.TickCount - model.Network.Overlord.LastUpdate) > Model.UPLINK_TIMEOUT) { //We havent recently sent/recieved so went a noop so check we are still connected. var req = new NetworkRequest { Verb = "NOOP", SourceID = model.LocalNode.ID, AuthKey = model.Network.Overlord.Secret }; var client = new Client(model.LocalNode); if (!client.Execute(req, model.Network.Overlord, 4000)) { if (network.State == ConnectionState.Connected) { Disconnect(); } } } workerEvent.WaitOne(10000); } else workerEvent.WaitOne(100); } }
public void Disconnect() { //Notify log off if (model.Network.State == ConnectionState.Connected) { var c = new Client(model.LocalNode); var verb = new UpdateVerb(); verb.Nodes.Add(new Node {ID = model.LocalNode.ID, Online = false}); c.Execute(verb, model.Network.Overlord, 3000); //Remove peer so we dont reconnect straight away most likely DetectedNode peer = peerFinder.Peers.Where(p => p.Address == model.Network.Overlord.Location).FirstOrDefault(); if (null != peer) peerFinder.RemovePeer(peer); model.Network.State = ConnectionState.Disconnected; } }
private void TransmitRequest(NetworkRequest req) { var client = new Client(serverNode); req.AuthKey = destination.Secret; if (!client.Execute(req, destination)) throw new Exception("Transmission failiure"); destination.LastUpdate = Environment.TickCount; }
private void item_Expanded_Async(object input) { var req = input as ExpandRequest; var c = new Client(model.LocalNode); var cmd = new BrowseVerb(shareInfo); cmd.Path = req.Path.FullPath; cmd.NoCache = bvm.NoCache; if (c.Execute(cmd, client)) { /* SafeObservableStatic.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action( delegate() { bvm.Status = "Download complete (" + cmd.Results.Count + " items)."; bvm.CurrentDirectory.Clear(); foreach (var result in cmd.Results) { if (result.IsFolder) { TreeViewItem x = new TreeViewItem(); x.Items.Add(_dummyNode); x.Expanded += new System.Windows.RoutedEventHandler(item_Expanded); x.Selected += new System.Windows.RoutedEventHandler(item_Selected); x.Header = result.Name; x.Tag = result; req.Item.Items.Add(x); } bvm.CurrentDirectory.Add(result); } } ));*/ } }
private void item_selected_async(object input) { var c = new Client(model.LocalNode); var cmd = new BrowseVerb(shareInfo); cmd.NoCache = bvm.NoCache; var ent = input as BrowsingFile; if (null != ent) cmd.Path = ent.FullPath; /* bvm.CurrentDirectory.Clear(); if (c.Execute(cmd, client)) { SafeObservableStatic.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action( delegate() { bvm.Status = "Download complete (" + cmd.Results.Count + ")."; foreach (var result in cmd.Results) { bvm.CurrentDirectory.Add(result); } } )); }*/ }
private void PopulateAsync(object o) { var fse = o as BrowsingFile; if (null != fse) { var c = new Client(model.LocalNode); var cmd = new BrowseVerb(shareInfo); cmd.Path = fse.FullPath; cmd.NoCache = bvm.NoCache; if (c.Execute(cmd, client)) { SafeObservableStatic.Dispatcher.Invoke(DispatcherPriority.Normal, new Action( delegate { bvm.Status = "Download complete (" + cmd.Results.Count + ")."; fse.IsPopulated = true; fse.ClearItems(); foreach (BrowsingFile result in cmd.Results) { result.Path = fse.FullPath; fse.AddItem(result); } bvm.CurrentItem = fse; bvm.IsBusy = false; } )); } } else { var c = new Client(model.LocalNode); var cmd = new BrowseVerb(shareInfo); cmd.NoCache = bvm.NoCache; if (c.Execute(cmd, client)) { SafeObservableStatic.Dispatcher.Invoke(DispatcherPriority.Normal, new Action( delegate { bvm.Status = "Download complete (" + cmd.Results.Count + ")."; var ent = new BrowsingFile(); foreach (BrowsingFile result in cmd.Results) { bvm.Root.Add(result); ent.AddItem(result); } ent.IsPopulated = true; bvm.CurrentItem = ent; bvm.IsBusy = false; } )); } } }