/// <summary> /// Start listing of a directory (intended to be used from C#). /// </summary> /// <param name="ctx">Runtime context.</param> /// <param name="directory">The path to the directory.</param> public Directory(Context ctx, string directory) { this.path = (PhpValue)directory; this.handle = PhpValue.FromClass(PhpDirectory.opendir(ctx, directory)); }
PhpValue Iterator.current() => PhpValue.FromClass(_list[_element]);
public PhpAlias GetAlias(ref PhpValue value, Context ctx, Type classContext) { var receiver = PhpValue.EnsureObject(ref value); var t = receiver.GetPhpTypeInfo(); PhpValue tmp; if (BinderHelpers.TryResolveDeclaredProperty(t, classContext, false, Name, out var prop)) { switch (Next.Operation) { case RuntimeChainOperation.Property: tmp = PhpValue.FromClass(prop.EnsureObject(ctx, receiver)); break; case RuntimeChainOperation.ArrayItem: tmp = PhpValue.Create(prop.EnsureArray(ctx, receiver)); break; case RuntimeChainOperation.End: return(prop.EnsureAlias(ctx, receiver)); default: throw new InvalidOperationException(); } } else { // Template: runtimeflds.Contains(key) ? runtimeflds.EnsureObject(key) : ( __get(key) ?? runtimeflds.EnsureObject(key)) var runtimeFields = t.GetRuntimeFields(receiver); if (runtimeFields == null || !runtimeFields.Contains(Name)) { // var __get = t.RuntimeMethods[TypeMethods.MagicMethods.__get]; if (__get != null) { // NOTE: magic methods must have public visibility, therefore the visibility check is unnecessary // int subkey1 = access.Write() ? 1 : access.Unset() ? 2 : access.Isset() ? 3 : 4; int subkey = Name.GetHashCode() ^ (1 << 4 /*subkey1*/); using (var token = new Context.RecursionCheckToken(ctx, receiver, subkey)) { if (!token.IsInRecursion) { tmp = __get.Invoke(ctx, receiver, Name); return(Next.GetAlias(ref tmp, ctx, classContext)); } } } } if (runtimeFields == null) { runtimeFields = t.EnsureRuntimeFields(receiver); } // switch (Next.Operation) { case RuntimeChainOperation.Property: tmp = PhpValue.FromClass(runtimeFields.EnsureItemObject(Name)); break; case RuntimeChainOperation.ArrayItem: tmp = PhpValue.Create(runtimeFields.EnsureItemArray(Name)); break; case RuntimeChainOperation.End: return(runtimeFields.EnsureItemAlias(Name)); default: throw new InvalidOperationException(); } } // chain: return(Next.GetAlias(ref tmp, ctx, classContext)); }
public RecursiveFilterIterator getChildren() { var childrenIt = ((RecursiveIterator)getInnerIterator()).getChildren(); object result = _ctx.Create(default(RuntimeTypeHandle), this.GetPhpTypeInfo(), PhpValue.FromClass(childrenIt)); return((RecursiveFilterIterator)result); }
/// <summary> /// Parses the <B>O</B> and <B>C</B> tokens. /// </summary> /// <param name="serializable">If <B>true</B>, the last token eaten was <B>C</B>, otherwise <B>O</B>.</param> object ParseObject(bool serializable) { Debug.Assert(_ctx != null); var seq = AddSeq(); // :{length}:"{classname}": Consume(Tokens.Colon); // : string class_name = ReadString().AsString(); // <length>:"classname" var tinfo = _ctx?.GetDeclaredType(class_name, true); // :{count}: Consume(Tokens.Colon); // : var count = (unchecked ((int)ReadInteger())); if (count < 0) { ThrowInvalidLength(); } Consume(Tokens.Colon); // bind to the specified class object obj; if (tinfo != null) { obj = tinfo.GetUninitializedInstance(_ctx); if (obj == null) { throw new ArgumentException(string.Format(LibResources.class_instantiation_failed, class_name)); } } else { // TODO: DeserializationCallback // __PHP_Incomplete_Class obj = new __PHP_Incomplete_Class(); throw new NotImplementedException("__PHP_Incomplete_Class"); } Consume(Tokens.BraceOpen); if (serializable) { // check whether the instance is PHP5.1 Serializable if (!(obj is global::Serializable)) { throw new ArgumentException(string.Format(LibResources.class_has_no_unserializer, class_name)); } PhpString serializedBytes; if (count > 0) { // add serialized representation to be later passed to unserialize var buffer = new byte[count]; if (_stream.Read(buffer, 0, count) < count) { ThrowEndOfStream(); } serializedBytes = new PhpString(buffer); } else { serializedBytes = PhpString.Empty; } // Template: Serializable::unserialize(data) ((global::Serializable)obj).unserialize(serializedBytes); } else { // parse properties while (--count >= 0) { // parse property name var nameval = Parse(); var pname = nameval.ToStringOrNull(); if (pname == null) { if (!nameval.IsInteger()) { ThrowInvalidDataType(); } pname = nameval.ToStringOrThrow(_ctx); } // parse property value var pvalue = Parse(); // set property SetProperty(obj, tinfo, pname, pvalue, _ctx); } // __wakeup var __wakeup = tinfo.RuntimeMethods[TypeMethods.MagicMethods.__wakeup]; if (__wakeup != null) { __wakeup.Invoke(_ctx, obj); } } Consume(Tokens.BraceClose); // seq.Value = PhpValue.FromClass(obj); return(obj); }
void InvokeDefaultHandler(string value = "") { DefaultHandler?.Invoke(_ctx, PhpValue.FromClass(this), (PhpValue)value); }
public override bool accept() => _callback.Invoke(_ctx, current(), key(), PhpValue.FromClass(this)).ToBoolean();
public virtual PhpValue current() => PhpValue.FromClass(this);
/// <inheritDoc /> public PhpValue fetch(PDO.PDO_FETCH fetch_style = PDO.PDO_FETCH.FETCH_USE_DEFAULT, int cursor_orientation = default(int), int cursor_offet = 0) { this.m_pdo.ClearError(); if (storedQueryResult != null) { return(FetchFromStored()); } else { try { PDO.PDO_FETCH style = this.m_fetchStyle; if ((int)fetch_style != -1 && Enum.IsDefined(typeof(PDO.PDO_FETCH), fetch_style)) { style = (PDO.PDO_FETCH)fetch_style; } PDO.PDO_FETCH_ORI ori = PDO.PDO_FETCH_ORI.FETCH_ORI_NEXT; if (Enum.IsDefined(typeof(PDO.PDO_FETCH_ORI), cursor_orientation)) { ori = (PDO.PDO_FETCH_ORI)cursor_orientation; } switch (ori) { case PDO.PDO_FETCH_ORI.FETCH_ORI_NEXT: break; default: throw new NotSupportedException(); } if (!this.m_dr.Read()) { return(PhpValue.False); } // Get the column schema, if possible, for the associative fetch if (this.m_dr_names == null) { this.m_dr_names = new string[m_dr.FieldCount]; if (this.m_dr.CanGetColumnSchema()) { var columnSchema = this.m_dr.GetColumnSchema(); for (int i = 0; i < m_dr.FieldCount; i++) { this.m_dr_names[i] = columnSchema[i].ColumnName; } } else { for (int i = 0; i < m_dr.FieldCount; i++) { this.m_dr_names[i] = this.m_dr.GetName(i); } } } switch (style) { case PDO.PDO_FETCH.FETCH_OBJ: return(this.ReadObj()); case PDO.PDO_FETCH.FETCH_ASSOC: return(PhpValue.Create(this.ReadArray(true, false))); case PDO.PDO_FETCH.FETCH_BOTH: case PDO.PDO_FETCH.FETCH_USE_DEFAULT: return(PhpValue.Create(this.ReadArray(true, true))); case PDO.PDO_FETCH.FETCH_NUM: return(PhpValue.Create(this.ReadArray(false, true))); case PDO.PDO_FETCH.FETCH_COLUMN: if (FetchColNo != -1) { m_pdo.HandleError(new PDOException("The column number for FETCH_COLUMN mode is not set.")); return(PhpValue.False); } return(this.ReadArray(false, true)[FetchColNo].GetValue()); case PDO.PDO_FETCH.FETCH_CLASS: if (FetchClassName == null) { m_pdo.HandleError(new PDOException("The className for FETCH_CLASS mode is not set.")); return(PhpValue.False); } var obj = _ctx.Create(FetchClassName, FetchClassCtorArgs ?? Array.Empty <PhpValue>()); return(PhpValue.FromClass(obj)); default: throw new NotImplementedException(); } } catch (System.Exception ex) { this.m_pdo.HandleError(ex); return(PhpValue.False); } } }
PhpValue /*object|array|WP_Error*/ PluginsApi(PhpValue result, string action, object args) { var arr = (PhpArray)PhpValue.FromClass(args); var log = NuGet.Common.NullLogger.Instance; switch (action) { case "query_plugins": var results = SearchFeed(arr, WpPluginPackageType, out var page, out var per_page, out var totalHits).ToList(); return(PhpValue.FromClass(new QueryPluginsResult { info = new PhpArray() { { "page", page }, { "pages", (totalHits / per_page) + ((totalHits % per_page) == 0 ? 0 : 1) }, { "results", results.Count }, }, plugins = new PhpArray(results.Select(_ => new PluginResult(_))), })); case "plugin_information": var versions = RegistrationResourceV3.GetPackageMetadata(PluginResult.SlugToId(arr["slug"].ToString()), true, true, log, CancellationToken.None) .Result .Select(PackageSearchMetadataFromJObject); var p = versions.LastOrDefault(); //var p = PackageMetadataResource.GetMetadataAsync(new PackageIdentity(arr["slug"].ToString(), new NuGet.Versioning.NuGetVersion("")), log, CancellationToken.None).Result; if (p != null) { var packageBaseAddress = ServiceIndexResourceV3.GetServiceEntryUri(ServiceTypes.PackageBaseAddress)?.AbsoluteUri; var id = p.Identity.Id.ToLowerInvariant(); var version = p.Identity.Version.ToNormalizedString().ToLowerInvariant(); var url = $"{packageBaseAddress}/{id}/{version}/{id}.{version}.nupkg"; return(PhpValue.FromClass(new PluginResult(p) { download_link = url })); } else { return(PhpValue.Null); } case "hot_tags": case "hot_categories": // // stdClass { "name" => array("name", "slug", "count") } // return PhpValue.FromClass( // new PhpArray() // { // }.AsStdClass() // ); return(false); // -> use regular WP API default: throw new ArgumentException(nameof(action)); } }
/// <summary> /// Defines WordPress configuration constants and initializes runtime before proceeding to <c>index.php</c>. /// </summary> static void Apply(Context ctx, WordPressConfig config, WpLoader loader) { // see wp-config.php: // WordPress Database Table prefix. ctx.Globals["table_prefix"] = (PhpValue)config.DbTablePrefix; // $table_prefix = 'wp_'; // SALT ctx.DefineConstant("AUTH_KEY", (PhpValue)config.SALT.AUTH_KEY); ctx.DefineConstant("SECURE_AUTH_KEY", (PhpValue)config.SALT.SECURE_AUTH_KEY); ctx.DefineConstant("LOGGED_IN_KEY", (PhpValue)config.SALT.LOGGED_IN_KEY); ctx.DefineConstant("NONCE_KEY", (PhpValue)config.SALT.NONCE_KEY); ctx.DefineConstant("AUTH_SALT", (PhpValue)config.SALT.AUTH_SALT); ctx.DefineConstant("SECURE_AUTH_SALT", (PhpValue)config.SALT.SECURE_AUTH_SALT); ctx.DefineConstant("LOGGED_IN_SALT", (PhpValue)config.SALT.LOGGED_IN_SALT); ctx.DefineConstant("NONCE_SALT", (PhpValue)config.SALT.NONCE_SALT); if (!string.IsNullOrEmpty(config.SiteUrl)) { ctx.DefineConstant("WP_SITEURL", config.SiteUrl); } if (!string.IsNullOrEmpty(config.HomeUrl)) { ctx.DefineConstant("WP_HOME", config.HomeUrl); } // multisite if (config.Multisite.Allow) { ctx.DefineConstant("WP_ALLOW_MULTISITE", (PhpValue)config.Multisite.Allow); } if (config.Multisite.Enable) { ctx.DefineConstant("MULTISITE", (PhpValue)config.Multisite.Enable); ctx.DefineConstant("SUBDOMAIN_INSTALL", (PhpValue)config.Multisite.DomainCurrentSite); ctx.DefineConstant("DOMAIN_CURRENT_SITE", (PhpValue)config.Multisite.DomainCurrentSite); ctx.DefineConstant("PATH_CURRENT_SITE", (PhpValue)config.Multisite.PathCurrentSite); ctx.DefineConstant("SITE_ID_CURRENT_SITE", (PhpValue)config.Multisite.SiteIDCurrentSite); ctx.DefineConstant("BLOG_ID_CURRENT_SITE", (PhpValue)config.Multisite.BlogIDCurrentSite); } // Additional constants if (config.Constants != null) { foreach (var pair in config.Constants) { ctx.DefineConstant(pair.Key, pair.Value); } } // $peachpie-wp-loader : WpLoader ctx.Globals["peachpie_wp_loader"] = PhpValue.FromClass(loader); // workaround HTTPS under proxy, // set $_SERVER['HTTPS'] = 'on' // https://wordpress.org/support/article/administration-over-ssl/#using-a-reverse-proxy if (ctx.IsWebApplication && ctx.GetHttpContext().Request.Headers["X-Forwarded-Proto"] == "https") { ctx.Server["HTTPS"] = "on"; } }
PhpValue IPhpCallable.ToPhpValue() => PhpValue.FromClass(this);
public static void DashboardWidget(this WpApp app, string widget_id, string widget_name, Action <TextWriter> htmlwriter) { app.AddFilter( "wp_dashboard_setup", new Action(() => app.Context.Call("wp_add_dashboard_widget", (PhpValue)widget_id, (PhpValue)widget_name, PhpValue.FromClass(new Action(() => htmlwriter(app.Context.Output)))))); }
private void ParseStep(XmlReader reader, Stack <ElementRecord> elementStack, ref TextRecord textChunk, PhpArray values, PhpArray indices) { string elementName; bool emptyElement; ElementRecord currentElementRecord = null; switch (reader.NodeType) { case XmlNodeType.Element: elementName = reader.Name; emptyElement = reader.IsEmptyElement; PhpArray attributeArray = new PhpArray(); //if (_processNamespaces && elementName.IndexOf(":") >= 0) //{ // string localName = elementName.Substring(elementName.IndexOf(":") + 1); // elementName = reader.NamespaceURI + _namespaceSeparator + localName; //} if (reader.MoveToFirstAttribute()) { do { if (_processNamespaces && reader.Name.StartsWith("xmlns:")) { string namespaceID = reader.Name.Substring(6); string namespaceUri = reader.Value; if (StartNamespaceDeclHandler != null) { StartNamespaceDeclHandler.Invoke(_ctx, PhpValue.FromClass(this), (PhpValue)namespaceID, (PhpValue)namespaceUri); } continue; } attributeArray.Add(EnableCaseFolding ? reader.Name.ToUpperInvariant() : reader.Name, reader.Value); }while (reader.MoveToNextAttribute()); } // update current top of stack if (elementStack.Count != 0) { currentElementRecord = elementStack.Peek(); UpdateValueAndIndexArrays(currentElementRecord, ref textChunk, values, indices, true); if (currentElementRecord.State == ElementState.Beginning) { currentElementRecord.State = ElementState.Interior; } } // push the element into the stack (needed for parse_into_struct) elementStack.Push( new ElementRecord() { ElementName = elementName, Level = reader.Depth, State = ElementState.Beginning, Attributes = (PhpArray)attributeArray.DeepCopy() }); if (StartElementHandler != null) { StartElementHandler.Invoke(_ctx, PhpValue.FromClass(this), (PhpValue)(EnableCaseFolding ? elementName.ToUpperInvariant() : elementName), (PhpValue)attributeArray); } else { InvokeDefaultHandler(); } if (emptyElement) { goto case XmlNodeType.EndElement; // and end the element immediately (<element/>, XmlNodeType.EndElement will not be called) } break; case XmlNodeType.EndElement: elementName = reader.Name; //if (_processNamespaces && elementName.IndexOf(":") >= 0) //{ // string localName = elementName.Substring(elementName.IndexOf(":") + 1); // elementName = reader.NamespaceURI + _namespaceSeparator + localName; //} // pop the top element record currentElementRecord = elementStack.Pop(); UpdateValueAndIndexArrays(currentElementRecord, ref textChunk, values, indices, false); if (EndElementHandler != null) { EndElementHandler.Invoke(_ctx, PhpValue.FromClass(this), (PhpValue)(EnableCaseFolding ? elementName.ToUpperInvariant() : elementName)); } else { InvokeDefaultHandler(); } break; case XmlNodeType.Whitespace: case XmlNodeType.Text: case XmlNodeType.CDATA: if (textChunk == null) { textChunk = new TextRecord() { Text = reader.Value }; } else { textChunk.Text += reader.Value; } if (CharacterDataHandler != null) { CharacterDataHandler.Invoke(_ctx, PhpValue.FromClass(this), (PhpValue)reader.Value); } else { InvokeDefaultHandler(reader.Value); } break; case XmlNodeType.ProcessingInstruction: if (ProcessingInstructionHandler != null) { ProcessingInstructionHandler.Invoke(_ctx, PhpValue.FromClass(this), (PhpValue)reader.Name, (PhpValue)reader.Value); } else { InvokeDefaultHandler(); } break; } }
protected override void DoAction(int action) { switch (action) { case 2: // start -> value { Result = (PhpValue)value_stack.array[value_stack.top - 1].yyval.obj; } return; case 3: // object -> OBJECT_OPEN members OBJECT_CLOSE { var elements = (List <KeyValuePair <string, PhpValue> >)value_stack.array[value_stack.top - 2].yyval.obj; var arr = new PhpArray(elements.Count); foreach (var item in elements) { arr.Add(Core.Convert.StringToArrayKey(item.Key), item.Value); } if (decodeOptions.Assoc) { yyval.obj = PhpValue.Create(arr); } else { yyval.obj = PhpValue.FromClass(arr.ToClass()); } } return; case 4: // object -> OBJECT_OPEN OBJECT_CLOSE { yyval.obj = PhpValue.FromClass(new stdClass()); } return; case 5: // members -> pair ITEMS_SEPARATOR members { var elements = (List <KeyValuePair <string, PhpValue> >)value_stack.array[value_stack.top - 1].yyval.obj; var result = new List <KeyValuePair <string, PhpValue> >(elements.Count + 1) { (KeyValuePair <string, PhpValue>)value_stack.array[value_stack.top - 3].yyval.obj }; result.AddRange(elements); yyval.obj = result; } return; case 6: // members -> pair { yyval.obj = new List <KeyValuePair <string, PhpValue> >() { (KeyValuePair <string, PhpValue>)value_stack.array[value_stack.top - 1].yyval.obj }; } return; case 7: // pair -> STRING NAMEVALUE_SEPARATOR value { yyval.obj = new KeyValuePair <string, PhpValue>((string)value_stack.array[value_stack.top - 3].yyval.obj, (PhpValue)value_stack.array[value_stack.top - 1].yyval.obj); } return; case 8: // array -> ARRAY_OPEN elements ARRAY_CLOSE { var elements = (List <PhpValue>)value_stack.array[value_stack.top - 2].yyval.obj; var arr = new PhpArray(elements.Count); foreach (var item in elements) { arr.Add(item); } yyval.obj = arr; } return; case 9: // array -> ARRAY_OPEN ARRAY_CLOSE { yyval.obj = PhpArray.NewEmpty(); } return; case 10: // elements -> value ITEMS_SEPARATOR elements { var elements = (List <PhpValue>)value_stack.array[value_stack.top - 1].yyval.obj; var result = new List <PhpValue>(elements.Count + 1) { (PhpValue)value_stack.array[value_stack.top - 3].yyval.obj }; result.AddRange(elements); yyval.obj = result; } return; case 11: // elements -> value { yyval.obj = new List <PhpValue>() { (PhpValue)value_stack.array[value_stack.top - 1].yyval.obj }; } return; case 12: // value -> STRING { yyval.obj = PhpValue.Create((string)value_stack.array[value_stack.top - 1].yyval.obj); } return; case 13: // value -> INTEGER { yyval.obj = PhpValue.FromClr(value_stack.array[value_stack.top - 1].yyval.obj); } return; case 14: // value -> DOUBLE { yyval.obj = PhpValue.FromClr(value_stack.array[value_stack.top - 1].yyval.obj); } return; case 15: // value -> object { yyval.obj = (PhpValue)value_stack.array[value_stack.top - 1].yyval.obj; } return; case 16: // value -> array { yyval.obj = PhpValue.Create((PhpArray)value_stack.array[value_stack.top - 1].yyval.obj); } return; case 17: // value -> TRUE { yyval.obj = PhpValue.True; } return; case 18: // value -> FALSE { yyval.obj = PhpValue.False; } return; case 19: // value -> NULL { yyval.obj = PhpValue.Null; } return; } }
private PhpValue ReadObj() { return(PhpValue.FromClass(this.ReadArray(true, false).ToClass())); }
static async Task <PhpValue> ProcessResponse(Context ctx, CURLResource ch, HttpWebResponse response) { // in case we are returning the response value var returnstream = ch.ProcessingResponse.Method == ProcessMethodEnum.RETURN ? new MemoryStream() : null; // handle headers if (!ch.ProcessingHeaders.IsEmpty) { var statusHeaders = HttpHeaders.StatusHeader(response) + HttpHeaders.HeaderSeparator; // HTTP/1.1 xxx xxx\r\n Stream outputHeadersStream = null; switch (ch.ProcessingHeaders.Method) { case ProcessMethodEnum.RETURN: case ProcessMethodEnum.STDOUT: outputHeadersStream = (returnstream ?? ctx.OutputStream); goto default; case ProcessMethodEnum.FILE: outputHeadersStream = ch.ProcessingHeaders.Stream.RawStream; goto default; case ProcessMethodEnum.USER: // pass headers one by one, // in original implementation we should pass them as they are read from socket: ch.ProcessingHeaders.User.Invoke(ctx, new[] { PhpValue.FromClass(ch), PhpValue.Create(statusHeaders) }); for (int i = 0; i < response.Headers.Count; i++) { var key = response.Headers.GetKey(i); var value = response.Headers.Get(i); if (key == null || key.Length != 0) { // header ch.ProcessingHeaders.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(key + ": " + value + HttpHeaders.HeaderSeparator), }); } } // \r\n ch.ProcessingHeaders.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(HttpHeaders.HeaderSeparator) }); break; default: if (outputHeadersStream != null) { await outputHeadersStream.WriteAsync(Encoding.ASCII.GetBytes(statusHeaders)); await outputHeadersStream.WriteAsync(response.Headers.ToByteArray()); } else { Debug.Fail("Unexpected ProcessingHeaders " + ch.ProcessingHeaders.Method); } break; } } var stream = response.GetResponseStream(); // gzip decode if necessary if (response.ContentEncoding == "gzip") // TODO: // && ch.AcceptEncoding.Contains("gzip") ?? { ch.VerboseOutput("Decompressing the output stream using GZipStream."); stream = new GZipStream(stream, CompressionMode.Decompress, leaveOpen: false); } // read into output stream: switch (ch.ProcessingResponse.Method) { case ProcessMethodEnum.STDOUT: await stream.CopyToAsync(ctx.OutputStream); break; case ProcessMethodEnum.RETURN: stream.CopyTo(returnstream); break; case ProcessMethodEnum.FILE: await stream.CopyToAsync(ch.ProcessingResponse.Stream.RawStream); break; case ProcessMethodEnum.USER: if (response.ContentLength != 0) { // preallocate a buffer to read to, // this should be according to PHP's behavior and slightly more effective than memory stream byte[] buffer = new byte[ch.BufferSize > 0 ? ch.BufferSize : 2048]; int bufferread; while ((bufferread = stream.Read(buffer, 0, buffer.Length)) > 0) { ch.ProcessingResponse.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(new PhpString(buffer.AsSpan(0, bufferread).ToArray())), // clone the array and pass to function }); } } break; case ProcessMethodEnum.IGNORE: break; } // stream.Dispose(); stream = null; // return((returnstream != null) ? PhpValue.Create(new PhpString(returnstream.ToArray())) : PhpValue.True); }
PhpValue /*object|array|WP_Error*/ PluginsApi(PhpValue result, string action, object args) { var arr = (PhpArray)PhpValue.FromClass(args); var log = NuGet.Common.NullLogger.Instance; switch (action) { case "query_plugins": int page = (int)arr["page"] - 1; int per_page = (int)arr["per_page"]; var searchFilter = new SearchFilter(true); // arr[browse|search|author|tag] var browse = arr["browse"].AsString(); var searchTerm = arr["search"].AsString() ?? arr["author"].AsString() ?? arr["tag"].AsString() ?? string.Empty; if (browse != null) { switch (browse) { case "beta": case "featured": //case "popular": case "recommended": // = premium default: break; } searchFilter = new SearchFilter(includePrerelease: browse == "beta"); } searchFilter.PackageTypes = WpPluginPackageType; //var results = PackageSearchResource.SearchAsync( // "", new SearchFilter(true), // skip: page * per_page, take: per_page, log: null, cancellationToken: CancellationToken.None).Result.ToList(); // TODO: list versions that are compatible with current wpdotnet ? var raw = RawSearchResourceV3.SearchPage(searchTerm, searchFilter, page * per_page, per_page, log, CancellationToken.None).Result; var results = (raw[JsonProperties.Data] as JArray ?? Enumerable.Empty <JToken>()) .OfType <JObject>() .Select(PackageSearchMetadataFromJObject) .ToList(); var totalHits = raw["totalHits"].ToObject <int>(); return(PhpValue.FromClass(new QueryPluginsResult { info = new PhpArray() { { "page", page }, { "pages", (totalHits / per_page) + ((totalHits % per_page) == 0 ? 0 : 1) }, { "results", results.Count }, }, plugins = new PhpArray(results.Select(_ => new PluginResult(_))), })); case "plugin_information": var p = RegistrationResourceV3.GetPackageMetadata(PluginResult.SlugToId(arr["slug"].ToString()), true, true, log, CancellationToken.None) .Result .Select(PackageSearchMetadataFromJObject) .FirstOrDefault(); //var p = PackageMetadataResource.GetMetadataAsync(new PackageIdentity(arr["slug"].ToString(), new NuGet.Versioning.NuGetVersion("")), log, CancellationToken.None).Result; if (p != null) { var packageBaseAddress = ServiceIndexResourceV3.GetServiceEntryUri(ServiceTypes.PackageBaseAddress)?.AbsoluteUri; var id = p.Identity.Id.ToLowerInvariant(); var version = p.Identity.Version.ToNormalizedString().ToLowerInvariant(); var url = $"{packageBaseAddress}/{id}/{version}/{id}.{version}.nupkg"; var plugin = new PluginResult(p); plugin.download_link = url; return(PhpValue.FromClass(plugin)); } else { return(PhpValue.Null); } case "hot_tags": case "hot_categories": return(PhpValue.Null); default: throw new ArgumentException(nameof(action)); } }