Skip to content

Commit

Permalink
Merge pull request #801 from gofractally/fracpack-port
Browse files Browse the repository at this point in the history
Fracpack for Python
  • Loading branch information
swatanabe authored Aug 14, 2024
2 parents bced8d5 + d956637 commit 9049afd
Show file tree
Hide file tree
Showing 71 changed files with 2,958 additions and 31,861 deletions.
1 change: 0 additions & 1 deletion doc/psidk/src/default-apps/events.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# events

{{#cpp-doc ::UserService::ServiceSchema}}
{{#cpp-doc ::UserService::EventIndex}}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ These help implement basic functionality:
- [psibase::serveSimpleUI]
- [psibase::serveActionTemplates]
- [psibase::servePackAction]
- [psibase::serveSchema]
- [psibase::WebContentRow]
- [psibase::storeContent]
- [psibase::serveContent]
Expand Down Expand Up @@ -117,6 +118,7 @@ std::optional<psibase::HttpReply> serveSys(psibase::HttpRequest request)
{{#cpp-doc ::psibase::serveSimpleUI}}
{{#cpp-doc ::psibase::serveActionTemplates}}
{{#cpp-doc ::psibase::servePackAction}}
{{#cpp-doc ::psibase::serveSchema}}
{{#cpp-doc ::psibase::WebContentRow}}
{{#cpp-doc ::psibase::storeContent}}
{{#cpp-doc ::psibase::serveContent}}
Expand Down
168 changes: 168 additions & 0 deletions libraries/psibase/common/include/psibase/schema.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,177 @@
#pragma once

#include <map>
#include <optional>
#include <psibase/AccountNumber.hpp>
#include <psibase/MethodNumber.hpp>
#include <psibase/db.hpp>
#include <psio/reflect.hpp>
#include <psio/schema.hpp>
#include <string>
#include <type_traits>
#include <vector>

namespace psibase
{
/// Represents the schema for a service
struct ServiceSchema
{
psibase::AccountNumber service;
psio::Schema types;
using ActionMap = std::map<psibase::MethodNumber, psio::schema_types::FunctionType>;
ActionMap actions;
using EventMap = std::map<psibase::MethodNumber, psio::schema_types::AnyType>;
EventMap ui;
EventMap history;
EventMap merkle;

private:
template <typename M>
static auto makeParams(psio::SchemaBuilder& builder, const psio::meta& ref)
-> psio::schema_types::Object
{
psio::schema_types::Object type;
auto nameIter = ref.param_names.begin();
auto nameEnd = ref.param_names.end();
auto i = ref.param_names.size();
forEachType(
typename M::SimplifiedArgTypes{},
[&](auto* t)
{
std::string name = nameIter == nameEnd ? "c" + std::to_string(i++) : *nameIter++;
type.members.push_back(
{std::move(name), builder.insert<std::remove_pointer_t<decltype(t)>>()});
});
return type;
}
template <typename T>
static auto makeResult(psio::SchemaBuilder& builder)
-> std::optional<psio::schema_types::AnyType>
{
if constexpr (std::is_void_v<T>)
{
return {};
}
else
{
return builder.insert<T>();
}
}
template <typename T>
static void makeActions(psio::SchemaBuilder& builder,
ActionMap& out,
std::vector<psio::schema_types::AnyType*>& eventTypes)
{
psio::reflect<T>::for_each(
[&](const psio::meta& ref, auto member)
{
using m = psio::MemberPtrType<decltype(member(std::declval<T*>()))>;
if constexpr (m::isFunction)
{
auto [pos, inserted] =
out.try_emplace(psibase::MethodNumber{ref.name},
psio::schema_types::FunctionType{
makeParams<m>(builder, ref),
makeResult<typename m::ReturnType>(builder)});
if (inserted)
{
eventTypes.push_back(&pos->second.params);
if (pos->second.result)
eventTypes.push_back(&*pos->second.result);
}
}
});
}
template <typename T>
static void makeEvents(psio::SchemaBuilder& builder,
EventMap& out,
std::vector<psio::schema_types::AnyType*>& eventTypes)
{
psio::reflect<T>::for_each(
[&](const psio::meta& ref, auto member)
{
using m = psio::MemberPtrType<decltype(member(std::declval<T*>()))>;
if constexpr (m::isFunction)
{
auto [pos, inserted] = out.try_emplace(psibase::MethodNumber{ref.name},
makeParams<m>(builder, ref));
if (inserted)
{
eventTypes.push_back(&pos->second);
}
}
});
}

public:
template <typename T>
static ServiceSchema make()
{
return make<T>(T::service);
}
/// Constructs a schema for a service.
template <typename T>
static ServiceSchema make(AccountNumber service)
{
ServiceSchema result{service};
std::vector<psio::schema_types::AnyType*> typeRefs;
psio::SchemaBuilder builder;
makeActions<T>(builder, result.actions, typeRefs);
if constexpr (requires { typename T::Events::Ui; })
{
makeEvents<typename T::Events::Ui>(builder, result.ui, typeRefs);
}
if constexpr (requires { typename T::Events::History; })
{
makeEvents<typename T::Events::History>(builder, result.history, typeRefs);
}
if constexpr (requires { typename T::Events::Merkle; })
{
makeEvents<typename T::Events::Merkle>(builder, result.merkle, typeRefs);
}
result.types = std::move(builder).build(typeRefs);
return result;
}

private:
const EventMap* getDb(psibase::DbId db) const
{
switch (db)
{
case psibase::DbId::uiEvent:
return &ui;
case psibase::DbId::merkleEvent:
return &merkle;
case psibase::DbId::historyEvent:
return &history;
default:
return nullptr;
}
}

public:
const psio::schema_types::AnyType* getType(psibase::DbId db, psibase::MethodNumber event)
{
if (const auto* dbTypes = getDb(db))
if (auto pos = dbTypes->find(event); pos != dbTypes->end())
return pos->second.resolve(types);
return nullptr;
}
std::vector<const psio::schema_types::AnyType*> eventTypes() const
{
std::vector<const psio::schema_types::AnyType*> result;
for (const auto* m : {&ui, &history, &merkle})
{
for (const auto& [_, type] : *m)
{
result.push_back(&type);
}
}
return result;
}
};
PSIO_REFLECT(ServiceSchema, service, types, actions, ui, history, merkle)

inline psio::schema_types::CustomTypes psibase_types()
{
auto result = psio::schema_types::standard_types();
Expand Down
35 changes: 35 additions & 0 deletions libraries/psibase/common/include/psibase/serveSchema.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <optional>
#include <psibase/Rpc.hpp>
#include <psibase/schema.hpp>
#include <psio/stream.hpp>
#include <psio/to_json.hpp>

namespace psibase
{

/// Handle `/schema` request
///
/// If `request` is a GET to `/schema`, then this returns JSON for a
/// ServiceSchema object.
///
/// If `request` doesn't match the above, then this returns `std::nullopt`.
template <typename Service>
std::optional<HttpReply> serveSchema(const HttpRequest& request)
{
if (request.method == "GET" && request.target == "/schema")
{
HttpReply reply{.contentType = "application/json"};
psio::vector_stream stream{reply.body};
AccountNumber service = {};
if constexpr (requires { Service::service; })
{
service = Service::service;
}
to_json(ServiceSchema::make<Service>(service), stream);
return reply;
}
return std::nullopt;
}
} // namespace psibase
3 changes: 3 additions & 0 deletions libraries/psibase/common/include/psibase/serveSimpleUI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <psibase/serveActionTemplates.hpp>
#include <psibase/servePackAction.hpp>
#include <psibase/serveSchema.hpp>
#include <psibase/serviceEntry.hpp>

namespace psibase
Expand Down Expand Up @@ -32,6 +33,8 @@ namespace psibase
return result;
if (auto result = servePackAction<Service>(request))
return result;
if (auto result = serveSchema<Service>(request))
return result;
if (IncludeRoot && request.method == "GET" && request.target == "/")
{
return HttpReply{
Expand Down
8 changes: 5 additions & 3 deletions libraries/psibase/common/tests/name.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ TEST_CASE("valid-method-names-check")
REQUIRE(psibase::MethodNumber("spiderman").value == 311625498215);
REQUIRE(psibase::MethodNumber("brucewayne").value == 56488722015273161);
REQUIRE(psibase::MethodNumber("anthonystark").value == 50913722085663764);
REQUIRE(psibase::MethodNumber("natasharomanoff").value == 13346021867974402139ull);
REQUIRE(psibase::MethodNumber("natasharomanoff").value == 6905860632893337981);
REQUIRE(psibase::MethodNumber("NATASHAROMANOFF").value == 679355919866582572);
REQUIRE(psibase::MethodNumber("abcdefghijklmnopqrstuvwxyz").value == 2393445670689189432);
}

TEST_CASE("convert-method-names-back-to-string")
Expand All @@ -102,6 +104,6 @@ TEST_CASE("convert-method-names-back-to-string")
REQUIRE(psibase::MethodNumber(311625498215).str() == "spiderman");
REQUIRE(psibase::MethodNumber(56488722015273161).str() == "brucewayne");
REQUIRE(psibase::MethodNumber(50913722085663764).str() == "anthonystark");
REQUIRE(psibase::MethodNumber(13346021867974402139ull).str() == "#hneunophpilcroch");
REQUIRE(psibase::MethodNumber(6905860632893337981).str() == "#psaoryoiluhlrpyn");
REQUIRE(psibase::MethodNumber(0).str() == "");
}
}
1 change: 0 additions & 1 deletion libraries/psibase/sdk/psibase-config.cmake.build
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ function(add_libs suffix)
add_library(psio${suffix} INTERFACE)
target_include_directories(psio${suffix} INTERFACE
@ROOT_SOURCE_DIR@/libraries/psio/include
@ROOT_SOURCE_DIR@/libraries/psio/consthash/include
@ROOT_SOURCE_DIR@/external/rapidjson/include
)
target_link_libraries(psio${suffix} INTERFACE
Expand Down
5 changes: 1 addition & 4 deletions libraries/psio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
enable_testing()

add_library( psio src/fpconv.c src/schema.cpp)
target_link_libraries( psio PUBLIC rapidjson consthash boost )
target_link_libraries( psio PUBLIC rapidjson boost )
target_include_directories( psio PUBLIC include )
add_compile_options( -Wall -Wstrict-aliasing )

Expand Down Expand Up @@ -38,14 +38,11 @@ target_sources( psio INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/include/psio/bytes.hpp
)

add_subdirectory( consthash )
add_subdirectory(tests)

if(IS_WASM)
target_link_libraries(psio PUBLIC wasm-base)
target_include_directories(psio PUBLIC ../psibase/common/include)
install(DIRECTORY consthash/include/consthash TYPE INCLUDE COMPONENT libpsibase)
install(FILES consthash/LICENSE DESTINATION ${CMAKE_INSTALL_DATADIR}/psibase/licenses RENAME LICENSE.consthash COMPONENT libpsibase)
install(DIRECTORY include/psio TYPE INCLUDE COMPONENT libpsibase FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h")
install(TARGETS psio ARCHIVE COMPONENT libpsibase)
endif()
2 changes: 0 additions & 2 deletions libraries/psio/consthash/CMakeLists.txt

This file was deleted.

21 changes: 0 additions & 21 deletions libraries/psio/consthash/LICENSE

This file was deleted.

40 changes: 0 additions & 40 deletions libraries/psio/consthash/README.md

This file was deleted.

Loading

0 comments on commit 9049afd

Please sign in to comment.