/// <summary> /// Get a supported class from the connection. Resource is unlocked after the action called is ended. /// </summary> public static void Get <T, C>(string path, out Teple <LockShared, T> resource) where C : Connection <C>, IGetValue <T>, new() { _lock.Take(); // get the type of connection Type sourceType = typeof(C); ArrayRig <IConnection> source; // check if there are currently any types of connections like this if (!_sources.TryGetValue(sourceType, out source)) { // create the dictionary source = new ArrayRig <IConnection>(); _sources[sourceType] = source; } // try get the connection C connection = source.GetSingle(c => c.Path == path) as C; // if the connection doesn't exist if (connection == null) { // create a new connection connection = new C(); connection.Path = path; // add to the source source.Add(connection); } // unlock the sources lock _lock.Release(); // get the resource connection.Get(out resource); }
public void Get(out Teple <LockShared, FileStream> fileStream) { if (!State.Is(ConnectionState.Open)) { Open(); } _locker.Take(); fileStream = new Teple <LockShared, FileStream>(_locker, _fileStream); }
/// <summary> /// Get the current stream writer for this connection. Makes the request if not already made. /// </summary> public void Get(out Teple <LockShared, ByteBuffer> stream) { if (!State.Is(ConnectionState.Open)) { Open(); } _locker.Take(); stream = new Teple <LockShared, ByteBuffer>(_locker, ByteStream); }
/// <summary> /// Pop an item from the cache. If the item has a single entry within the cache /// the size of the cache will be reduced. /// </summary> public void Pop() { _lock.Take(); // move to the next queued item if (!_queue.Next()) { _lock.Release(); return; } // get the lookup record Teple <long, long, TValue> current = _lookup[_queue.Current]; while (current.ArgA == 0) { if (!_queue.Next()) { _lock.Release(); return; } current = _lookup[_queue.Current]; } _peeked = false; // are there duplicate entries for the current item if (current.ArgA == 1) { // no, decrement the size of the current item _size -= current.ArgB; // remove the lookup entry _lookup.Remove(_queue.Current); _lock.Release(); // is the callback set? if (_onRemoved.Action != null) { // yes, run it _onRemoved.Run(current.ArgC); } } else { // yes, decrement the number of cache entries --current.ArgA; _lock.Release(); } }
public void UpdateAsset(string name) { _assetLock.Take(); long milliseconds = _time.Milliseconds; if (Assets.ContainsKey(name)) { Teple <long, long> stats = Assets[name]; ++stats.ArgA; stats.ArgB += milliseconds - AssetTicks[name]; AssetTicks[name] = milliseconds; } else { Assets.Add(name, new Teple <long, long>(1, 0)); AssetTicks.Add(name, milliseconds); } ++AssetCount; _assetLock.Release(); }
//-------------------------------------------// /// <summary> /// Run loop of the text template. /// </summary> protected void Run(string str, int index, IAction <StringBuilder> onRan, TreeSearch <char, Teple <string, ActionRoll <StringBuilder, string, int> > > .DynamicSearch search) { int end = index + Global.BufferSizeLocal; if (end > str.Length) { end = str.Length; } Teple <string, ActionRoll <StringBuilder, string, int> > result = null; // iterate the string for (int i = index; i < end; ++i) { // has a replacement string been found? if (search.Next(str[i])) { // yes, set the current result result = search.Values.Pop(); } else { // no, has a replacement been found? if (result != null) { // yes, append the replacement if (result.ArgA != null) { onRan.ArgA.Append(result.ArgA); } if (result.ArgB != null) { result.ArgB.Run(onRan.ArgA, str, str.Length - 1); } result = null; } // append the non-matching character onRan.ArgA.Append(str[i]); } } // was the last character to be replaced? if (result != null) { // yes, append the replacement if (result.ArgA != null) { onRan.ArgA.Append(result.ArgA); } if (result.ArgB != null) { result.ArgB.Run(onRan.ArgA, str, str.Length - 1); } } if (index < end) { ManagerUpdate.Control.AddSingle(Run, str, index, onRan, search); } else { onRan.Run(); } }
/// <summary> /// Send data to the remote host /// </summary> public void Send(byte[] buffer, int index, int count, IAction onSent = null) { // skip 0 bytes if (count == 0) { return; } if (onSent != null) { _callbackLock.Take(); // enqueue bytes in the buffer var length = _sendBuffer.TakeItem().EnqueueGetCount(buffer, index, count); _sendBuffer.Release(); if (_currentCallbackAction == null) { _currentCallbackAction = onSent; _currentCallbackIndex = _lastCallbackIndex = length; } else { _lastCallbackIndex = length - _lastCallbackIndex; _callbacks.Enqueue(Teple.New(_lastCallbackIndex, onSent)); } _callbackLock.Release(); } else { // enqueue bytes from the stream _sendBuffer.TakeItem().Enqueue(buffer, index, count); _sendBuffer.Release(); } // is the socket currently sending? if (_sendLock.TryTake) { // ensure not disposing if (_disposing) { _sendLock.Release(); return; } try { StartSend(); } catch (SocketException ex) { _sendLock.Release(); if (ex.SocketErrorCode == SocketError.ConnectionReset) { return; } ProcessError(ex); } catch (Exception ex) { _sendLock.Release(); // handle the error outside the lock ProcessError(ex); } } }
/// <summary> /// Load this elements children. This is the final function of all built elements. /// </summary> protected async void Build(Ticker ticker, Element element, Elements elements) { if (_singleChildren != null) { // initiaize the parent cache used to keep track of the desired indices of added elements. // Once an element is added to the cache an index is used to insert each new child as they // are built Dictionary <string, Teple <Element, int> > parentCache = new Dictionary <string, Teple <Element, int> >(); // iterate the children to action foreach (var child in _singleChildren) { ticker.Push(); switch (child.Value.Action) { case BuilderAction.Replace: ManagerUpdate.Control.AddSingle(child.Value.BuildReplaceChild, ticker, elements, element, child.Key); break; case BuilderAction.Add: if (parentCache == null) { parentCache = new Dictionary <string, Teple <Element, int> >(); } ; Teple <Element, int> next; if (parentCache.TryGetValue(child.Key, out next)) { ++next.ArgB; } else { next = new Teple <Element, int>(element.FindChild(child.Key), 0); next.ArgB = next.ArgA.ChildCount; parentCache.Add(child.Key, next); } ManagerUpdate.Control.AddSingle(child.Value.BuildAddedChild, ticker, elements, next.ArgA, next.ArgB); break; default: var childElement = element.FindChild(child.Key); if (childElement == null) { Log.Error("Child element '" + child.Key + "' not found in '" + element + "'."); } ManagerUpdate.Control.AddSingle(child.Value.Build, ticker, childElement, elements); break; } } } if (_multiChildren != null) { // initiaize the parent cache used to keep track of the desired indices of added elements. // Once an element is added to the cache an index is used to insert each new child as they // are built Dictionary <string, Teple <Element, int> > parentCache = new Dictionary <string, Teple <Element, int> >(); // iterate the children to action foreach (var collection in _multiChildren) { foreach (var child in collection.Value) { ticker.Push(); switch (child.Action) { case BuilderAction.Replace: // add an action to build the replacement child ManagerUpdate.Control.AddSingle(child.BuildReplaceChild, ticker, elements, element, collection.Key); break; case BuilderAction.Add: // create a cache of references if (parentCache == null) { parentCache = new Dictionary <string, Teple <Element, int> >(); } ; Teple <Element, int> next; if (parentCache.TryGetValue(collection.Key, out next)) { ++next.ArgB; } else { next = new Teple <Element, int>(element.FindChild(collection.Key), 0); next.ArgB = next.ArgA.ChildCount; parentCache.Add(collection.Key, next); } ManagerUpdate.Control.AddSingle(child.BuildAddedChild, ticker, elements, next.ArgA, next.ArgB); break; case BuilderAction.Remove: var removeElement = element.FindChild(collection.Key); if (removeElement == null) { Log.Error("Child element '" + collection.Key + "' was not found in '" + element + "' to be removed."); } else { removeElement.Remove(); } break; default: var childElement = element.FindChild(collection.Key); if (childElement == null) { Log.Error("Child element '" + collection.Key + "' not found in '" + element + "' to be altered."); } else { ManagerUpdate.Control.AddSingle(child.Build, ticker, childElement, elements); } break; } } } } // have any attributes been specified? if (Attributes != null) { // yes, iterate the attributes foreach (var attribute in Attributes) { if (attribute.Value.ArgB == null) { element.SetAttribute(attribute.Key, attribute.Value.ArgA); } else if (attribute.Value.ArgA == null) { element.RemoveAttribute(attribute.Key); } else { element.SetAttribute(attribute.Key, await attribute.Value.ArgB.RunAsync() ?? attribute.Value.ArgA); } } } // has the content been specified? if (Content != null) { // yes, iterate and add the content foreach (var content in Content) { element.Content.Add(content.ArgB == null ? content.ArgA : await content.ArgB.RunAsync() ?? content.ArgA); } } ticker.Pull(); }
//----------------------------------// /// <summary> /// Refresh the headers from the header index. /// </summary> protected unsafe void RefreshHeaders() { // set the builder index _builder.Length = _refreshBuilderIndex; if (_refreshBuilderIndex == 0) { _builder.Append(_version); _builder.Append(Chars.Space); _builder.Append(_statusCode); _builder.Append(Chars.Space); _builder.AppendLine(_statusDescription); } if (_refreshDefinedHeaders) { _refreshDefinedHeaders = false; // iterate the headers from the index to be refreshed for (int i = _refreshDefinedHeaderIndex; i < _definedHeaders.Count; ++i) { // persist the header Teple <HttpResponseHeader, Teple <string, int> > header = _definedHeaders[i]; header.ArgB.ArgB = _builder.Length; string value; if (_definedSingles.TryGetValue(header.ArgA, out value)) { // yes, check refresh if (!_refreshDefinedHeaders) { // yes, set the header index _refreshDefinedHeaderIndex = i; _refreshBuilderIndex = header.ArgB.ArgB; // flip the refresh flag _refreshDefinedHeaders = true; } // remove the single-shot header from the collection _definedSingles.Remove(header.ArgA); if (header.ArgB.ArgA == null) { // remove the header from the collection _definedHeaders.RemoveQuick(i); --i; } // append the header key and value _builder.Append(header.ArgA.GetString()); _builder.Append(Chars.Colon); _builder.Append(Chars.Space); _builder.AppendLine(value); } else { // append the header key and value _builder.Append(header.ArgA.GetString()); _builder.Append(Chars.Colon); _builder.Append(Chars.Space); _builder.AppendLine(header.ArgB.ArgA); } } _refreshCustomHeaders = true; _refreshCustomHeaderIndex = 0; } if (_refreshCustomHeaders) { _refreshCustomHeaders = false; // iterate the headers from the index to be refreshed for (int i = _refreshCustomHeaderIndex; i < _customHeaders.Count; ++i) { // persist the header Teple <string, Teple <string, int> > header = _customHeaders[i]; header.ArgB.ArgB = _builder.Length; string value; if (_customSingles.TryGetValue(header.ArgA, out value)) { // yes, check refresh if (!_refreshCustomHeaders) { // yes, set the header index _refreshCustomHeaderIndex = i; _refreshBuilderIndex = header.ArgB.ArgB; // flip the refresh flag _refreshCustomHeaders = true; } // remove the single-shot header from the collection _customSingles.Remove(header.ArgA); if (header.ArgB.ArgA == null) { // remove the header from the collection _customHeaders.RemoveQuick(i); --i; } // append the header key and value _builder.Append(header.ArgA); _builder.Append(Chars.Colon); _builder.Append(Chars.Space); _builder.AppendLine(value); } else { // append the header key and value _builder.Append(header.ArgA); _builder.Append(Chars.Colon); _builder.Append(Chars.Space); _builder.AppendLine(header.ArgB.ArgA); } } } foreach (var single in _definedSingles) { // append the header key and value _builder.Append(single.Key.GetString()); _builder.Append(Chars.Colon); _builder.Append(Chars.Space); _builder.AppendLine(single.Value); } _definedSingles.Clear(); foreach (var single in _customSingles) { // append the header key and value _builder.Append(single.Key); _builder.Append(Chars.Colon); _builder.Append(Chars.Space); _builder.AppendLine(single.Value); } _customSingles.Clear(); _builder.AppendLine(); // should the status code be reset? if (_statusCode != 200) { // yes, reset it StatusCode = 200; // reset the status description _statusDescription = "OK"; } }
/// <summary> /// On socket data being received. /// </summary> private unsafe void OnReceiveSocketData(IAsyncResult ar) { int count = 0; try { // end the receive count = Socket.EndReceiveFrom(ar, ref _receiveEndPoint); } catch (Exception ex) { // release the read lock _syncLock.ReleaseRead(); ProcessError(ex); return; } if (count > 0) { // is the received buffer chunked? byte flag = _receiveBuffer[0]; if (flag < 60 || flag >= 188) { count -= ChunkHeaderSize; int chunkId; int chunkIndex; int chunkCount; // sanity check for correct number of bytes received if (count < 0) { _syncLock.ReleaseRead(); ProcessError("Socket didn't receive enough data for chunked information."); return; } // yes, read the chunk details fixed(byte *intP = &_receiveBuffer[1]) { chunkId = *(int *)intP; } fixed(byte *intP = &_receiveBuffer[5]) { chunkIndex = *(int *)intP; } fixed(byte *intP = &_receiveBuffer[9]) { chunkCount = *(int *)intP; } // sanity check for the chunk data being valid if (chunkIndex >= chunkCount) { _syncLock.ReleaseRead(); ProcessError("Socket received invalid chunk index and count information."); return; } // write ChunkedGram chunkedGram; if (_receivedChunks.TryGetValue(chunkId, out chunkedGram)) { chunkedGram.Length += count; chunkedGram.Chunks.Insert(Teple.New(count, _receiveBuffer), chunkIndex); // have all chunks been added? if (chunkedGram.Chunks.Count == chunkCount) { // yes, remove from the collection _receivedChunks.Remove(chunkId); // create a byte buffer for the entire message byte[] result = new byte[chunkedGram.Length]; int index = 0; foreach (var chunk in chunkedGram.Chunks) { int length = chunk.ArgA; Micron.CopyMemory(chunk.ArgB, ChunkHeaderSize, result, index, length); index += length; } // reference the endpoint from which the data was received IPEndPoint endpoint = (IPEndPoint)_receiveEndPoint; // run the callback _onReceive.AddRun(ActionSet.New(OnReceive, endpoint, result, chunkedGram.Length)); } else { // no, create a new receive buffer _receiveBuffer = BufferCache.Get(); } } else { chunkedGram = new ChunkedGram { Chunks = new ArrayRig <Teple <int, byte[]> >(chunkCount), Timestamp = Time.Timestamp }; _receivedChunks.Add(chunkId, chunkedGram); chunkedGram.Chunks.Add(Teple.New(count, _receiveBuffer)); chunkedGram.Length += count; // create a new receive buffer _receiveBuffer = BufferCache.Get(); } } else { // no, copy the received buffer --count; byte[] buffer = BufferCache.Get(count); Micron.CopyMemory(_receiveBuffer, 1, buffer, 0, count); // reference the endpoint from which the data was received IPEndPoint endpoint = (IPEndPoint)_receiveEndPoint; // run the callback _onReceive.AddRun(ActionSet.New(OnReceive, endpoint, buffer, count)); } } if (_receivedChunks.Count > 0) { // check for any chunked data timeouts ArrayRig <int> toRemove = null; foreach (var chunkedGram in _receivedChunks) { if (Time.Timestamp - chunkedGram.Value.Timestamp > ChunkedGramTimeout) { if (toRemove == null) { toRemove = new ArrayRig <int>(); } toRemove.Add(chunkedGram.Key); } } if (toRemove != null) { foreach (var chunkId in toRemove) { ChunkedGram chunked; if (_receivedChunks.TryGetValue(chunkId, out chunked)) { _receivedChunks.Remove(chunkId); chunked.Chunks.Dispose(); } } } } // release the read lock _syncLock.ReleaseRead(); // create the endpoint for receiving data _receiveEndPoint = new IPEndPoint(RemoteEndPoint.Address, RemoteEndPoint.Port); try { // start receiving again Socket.BeginReceiveFrom(_receiveBuffer, 0, Global.BufferSizeLocal, SocketFlags.None, ref _receiveEndPoint, OnReceiveSocketData, null); } catch (Exception ex) { ProcessError(ex); return; } }
public bool MoveNext() { if (_first) { _first = false; return(_node != null); } while (true) { // is there the potential to iterate over the current nodes children? if (_node.ArraySet) { // push current enumerator onto the stack _nodeEnumerators.Add(new Teple <IEnumerator <Node>, bool>(_currentEnumerator, _list)); _currentEnumerator = _node.Array.GetEnumerator(); if (_currentEnumerator.MoveNext()) { _list = true; _node = _currentEnumerator.Current; return(true); } } if (_node.DictionarySet) { // push current enumerator onto the stack _nodeEnumerators.Add(new Teple <IEnumerator <Node>, bool>(_currentEnumerator, _list)); _currentEnumerator = _node.Dictionary.Values.GetEnumerator(); if (_currentEnumerator.MoveNext()) { _list = false; _node = _currentEnumerator.Current; return(true); } } while (true) { // move the current enumerator if (_currentEnumerator.MoveNext()) { _node = _currentEnumerator.Current; return(true); } if (_list) { _list = false; if (_node.DictionarySet) { // set the first enumerator as this nodes list _currentEnumerator = _node.Dictionary.Values.GetEnumerator(); if (_currentEnumerator.MoveNext()) { _node = _currentEnumerator.Current; return(true); } } } // any node enumerators to pop? if (_nodeEnumerators.Count == 0) { return(false); } // pop last enumerator off stack if it exists Teple <IEnumerator <Node>, bool> next = _nodeEnumerators.Pop(); _currentEnumerator = next.ArgA; _list = next.ArgB; // move up a node _node = _node.Parent; } } }
/// <summary> /// Add the value or retrieve an existing value in a single threadsafe call. /// </summary> public TValue AddOrGet(TKey key, TValue item) { _lock.Take(); // get the item size long itemSize = _getItemSize == null ? 1L : _getItemSize(item); // does the item already exist in the cache? Teple <long, long, TValue> cached; if (_lookup.TryGetValue(key, out cached) && cached.ArgA > 0) { // yes, add the item to the end of the queue _queue.Enqueue(key); // increment the number of duplicate items in the lookup ++cached.ArgA; _lock.Release(); return(cached.ArgC); } // is the item too large for the cache? if (itemSize > MaxItemSize) { // yes, skip adding it _lock.Release(); return(item); } // add the item size to the current total _size += itemSize; // add the item to the current queue _queue.Enqueue(key); // add the item to the lookup _lookup[key] = new Teple <long, long, TValue>(1L, itemSize, item); // has the cache overflowed? if (_size > MaxSize) { // while the size has overflowed, iterate while (_size > MaxSize) { // move to the next queued item _queue.Next(); _peeked = false; // get the lookup record Teple <long, long, TValue> current = _lookup[_queue.Current]; if (current.ArgA == 0) { continue; } // are there duplicate entries for the current item if (current.ArgA == 1) { // no, decrement the size of the current item _size -= current.ArgB; // remove the lookup entry _lookup.Remove(_queue.Current); // is the callback set? if (_onRemoved.Action != null) { // yes, run it _onRemoved.Run(current.ArgC); } } else { // yes, decrement the number of cache entries --current.ArgA; } } } _lock.Release(); return(item); }