Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix: graphql resolution #34

Merged
merged 1 commit into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 1 addition & 32 deletions cli/auth/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"fmt"
"github.com/nats-io/nats.go/jetstream"
"go.uber.org/zap"
"io"
"net/http"
"os"
"slices"
Expand Down Expand Up @@ -108,38 +107,8 @@ func (r *Resource) ShareOwnership(newUser UserId, currentUser *User, keepPermiss
return nil
}

// ApplyPerms applies permissions to the Resource identified by the given StateId. It retrieves the permissions from the
// cache if available, otherwise it retrieves them from the key
func (r *Resource) getPermissions(id *glue.StateId, ctx context.Context, logger *zap.Logger) (CreatePermissions, error) {
if cached, found := cache.Load(id.Name()); found {
return cached.(CreatePermissions), nil
}

result, err := os.CreateTemp("", "")
if err != nil {
return CreatePermissions{}, err
}

env := map[string]string{"STATE_ID": id.String()}
glu := glue.NewGlue("", glue.GetPermissions, make([]any, 0), result.Name())
glu.Execute(ctx, make(http.Header), logger, env, nil, id)

data, err := io.ReadAll(result)
if err != nil {
return CreatePermissions{}, err
}

var perms CreatePermissions
if err := json.Unmarshal(data, &perms); err != nil {
return CreatePermissions{}, err
}

cache.Store(id.Name(), perms)
return perms, nil
}

func (r *Resource) ApplyPerms(id *glue.StateId, ctx context.Context, logger *zap.Logger) bool {
perms, err := r.getPermissions(id, ctx, logger)
perms, err := r.getOrCreatePermissions(id, ctx, logger)
if err != nil {
logger.Error("failed to get permissions", zap.Error(err))
return false
Expand Down
82 changes: 42 additions & 40 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,50 +271,52 @@ func execute(args []string, options map[string]string) int {
}
}

outputBillingStatus := func() {
costC := func(num interface{}, basis int) float64 {
return float64(num.(int)) * float64(basis) / 10_000_000
}

costA := func(dur interface{}, basis int) float64 {
duration := dur.(time.Duration)
seconds := duration.Seconds()
return float64(basis) * seconds / 100_000
}
/*
outputBillingStatus := func() {
costC := func(num interface{}, basis int) float64 {
return float64(num.(int)) * float64(basis) / 10_000_000
}

avg := func(dur interface{}, count interface{}) time.Duration {
seconds := dur.(time.Duration).Seconds()
return time.Duration(seconds/float64(count.(int))) * time.Second
}
costA := func(dur interface{}, basis int) float64 {
duration := dur.(time.Duration)
seconds := duration.Seconds()
return float64(basis) * seconds / 100_000
}

e, _ := billings.Load("e")
o, _ := billings.Load("o")
ac, _ := billings.Load("ac")
a, _ := billings.Load("a")

ecost := costC(e, cfg.Extensions.Billing.Costs.Entities.Cost)
ocost := costC(o, cfg.Extensions.Billing.Costs.Orchestrations.Cost)
acost := costA(a, cfg.Extensions.Billing.Costs.Activities.Cost)

logger.Warn("Billing estimate",
zap.Any("launched entities", e),
zap.String("entity cost", fmt.Sprintf("$%.2f", ecost)),
zap.Any("launched orchestrations", o),
zap.String("orchestration cost", fmt.Sprintf("$%.2f", ocost)),
zap.Any("activity time", a),
zap.Any("activities launced", ac),
zap.Any("average activity time", avg(a, ac)),
zap.String("activity cost", fmt.Sprintf("$%.2f", acost)),
zap.String("total estimate", fmt.Sprintf("$%.2f", ecost+ocost+acost)),
)
}
avg := func(dur interface{}, count interface{}) time.Duration {
seconds := dur.(time.Duration).Seconds()
return time.Duration(seconds/float64(count.(int))) * time.Second
}

go func() {
ticker := time.NewTicker(3 * time.Second)
for range ticker.C {
outputBillingStatus()
e, _ := billings.Load("e")
o, _ := billings.Load("o")
ac, _ := billings.Load("ac")
a, _ := billings.Load("a")

ecost := costC(e, cfg.Extensions.Billing.Costs.Entities.Cost)
ocost := costC(o, cfg.Extensions.Billing.Costs.Orchestrations.Cost)
acost := costA(a, cfg.Extensions.Billing.Costs.Activities.Cost)

logger.Warn("Billing estimate",
zap.Any("launched entities", e),
zap.String("entity cost", fmt.Sprintf("$%.2f", ecost)),
zap.Any("launched orchestrations", o),
zap.String("orchestration cost", fmt.Sprintf("$%.2f", ocost)),
zap.Any("activity time", a),
zap.Any("activities launced", ac),
zap.Any("average activity time", avg(a, ac)),
zap.String("activity cost", fmt.Sprintf("$%.2f", acost)),
zap.String("total estimate", fmt.Sprintf("$%.2f", ecost+ocost+acost)),
)
}
}()

go func() {
ticker := time.NewTicker(3 * time.Second)
for range ticker.C {
outputBillingStatus()
}
}()
*/

billingStream, err := js.CreateOrUpdateStream(ctx, jetstream.StreamConfig{
Name: "billing",
Expand Down
1 change: 1 addition & 0 deletions cli/lib/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@ func authorize(
return ctx, false
}
if user, ok := auth.ExtractUser(request, config); ok {
logger.Info("Authenticating with user", zap.Any("user", user))
ctx = auth.DecorateContextWithUser(ctx, user)
}
resource, err := rm.DiscoverResource(ctx, id, logger, preventCreation)
Expand Down
3 changes: 1 addition & 2 deletions src/DurableClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@
public function __construct(
private EntityClientInterface $entityClient,
private OrchestrationClientInterface $orchestrationClient
) {
}
) {}

Check warning on line 42 in src/DurableClient.php

View check run for this annotation

Codecov / codecov/patch

src/DurableClient.php#L42

Added line #L42 was not covered by tests

public static function get(string $apiHost = 'http://localhost:8080'): self
{
Expand Down
66 changes: 38 additions & 28 deletions src/Gateway/Graph/SchemaGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,34 @@
namespace Bottledcode\DurablePhp\Gateway\Graph;

use Bottledcode\DurablePhp\State\Attributes\Name;

use Bottledcode\DurablePhp\State\EntityId;
use Bottledcode\DurablePhp\State\OrchestrationInstance;
use DateTime;
use DateTimeImmutable;
use DateTimeInterface;
use DI\Definition\Helper\AutowireDefinitionHelper;
use DI\Definition\Helper\CreateDefinitionHelper;

use const T_STRING;

class SchemaGenerator
{
public array $handlers = [];

private string $bootstrap;

private string $root;

private array $scalars = [
'Any',
'Void',
'State',
'Date',
];

private array $states = [];

private array $searchedStates = [];

public function __construct()
Expand All @@ -57,13 +68,13 @@
['mutation' => $mutations, 'query' => $queries] = $this->findPhpFiles($projectRoot);

$flipped = array_flip($this->searchedStates);
foreach($this->states as $realName => $properties) {
if(empty(trim($properties))) {
foreach ($this->states as $realName => $properties) {
if (empty(trim($properties))) {

Check warning on line 72 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L71-L72

Added lines #L71 - L72 were not covered by tests
continue;
}

$rootName = $this->findRootName($realName, $flipped);
if($rootName === $realName) {
if ($rootName === $realName) {

Check warning on line 77 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L77

Added line #L77 was not covered by tests
// todo: warn?
continue;
}
Expand All @@ -79,7 +90,7 @@

{$name}(id: ID!): {$name}Snapshot
EOF;
$this->handlers['queries'][] = ['op' => 'entity', 'op-name' => $name];
$this->handlers['queries'][] = ['op' => 'entity', 'op-name' => $name, 'realName' => $realName];

Check warning on line 93 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L93

Added line #L93 was not covered by tests

}
$scalars = array_map(fn($x) => 'scalar ' . $x, array_unique($this->scalars));
Expand Down Expand Up @@ -142,7 +153,7 @@
{
$name = basename($filename, '.php');
$parsed = MetaParser::parseFile($contents);
$realName = $parsed->namespace . "\\" . $name;
$realName = $parsed->namespace . '\\' . $name;

Check warning on line 156 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L156

Added line #L156 was not covered by tests
$name = ucfirst($name);

$mutation = <<<GRAPHQL
Expand All @@ -157,8 +168,7 @@

GRAPHQL;


$this->handlers['mutations'][] = ['op' => 'StartOrchestration', 'op-name' => "StartNew{$name}Orchestration", 'name' => $realName,];
$this->handlers['mutations'][] = ['op' => 'StartOrchestration', 'op-name' => "StartNew{$name}Orchestration", 'name' => $realName];

Check warning on line 171 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L171

Added line #L171 was not covered by tests
$this->handlers['queries'][] = ['op' => 'OrchestrationStatus', 'op-name' => "{$name}Status", 'name' => $realName];

$waitForExternalEventCalls = [];
Expand All @@ -167,7 +177,7 @@
$nextStringIsArgument = false;
foreach ($tokens as $token) {
if (is_array($token)) {
if ($token[0] === \T_STRING && $token[1] === 'waitForExternalEvent') {
if ($token[0] === T_STRING && $token[1] === 'waitForExternalEvent') {

Check warning on line 180 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L180

Added line #L180 was not covered by tests
$waitForExternalEventFound = true;
} elseif ($waitForExternalEventFound && $token[0] === T_CONSTANT_ENCAPSED_STRING) {
$waitForExternalEventCalls[] = trim($token[1], '\'"');
Expand All @@ -190,20 +200,20 @@
$parsed = MetaParser::parseFile($contents);

$realName = basename($filename, '.php');
$realName = $parsed->namespace . "\\" . $realName;
$realName = $parsed->namespace . '\\' . $realName;

Check warning on line 203 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L203

Added line #L203 was not covered by tests

foreach($parsed->attributes as $attribute) {
if($attribute['name'] === 'Name' || $attribute['name'] === Name::class) {
foreach ($parsed->attributes as $attribute) {
if ($attribute['name'] === 'Name' || $attribute['name'] === Name::class) {

Check warning on line 206 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L205-L206

Added lines #L205 - L206 were not covered by tests
$className = ucfirst(trim($attribute['args'][0]['type'], '"\''));
goto found;
}
}

if(str_contains($contents, 'EntityState')) {
if (str_contains($contents, 'EntityState')) {

Check warning on line 212 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L212

Added line #L212 was not covered by tests
$properties = [];
foreach($parsed->properties as ['type' => $type, 'name' => $name]) {
foreach ($parsed->properties as ['type' => $type, 'name' => $name]) {

Check warning on line 214 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L214

Added line #L214 was not covered by tests
[$type, $scalar] = $this->extractScalars($type);
if($scalar) {
if ($scalar) {

Check warning on line 216 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L216

Added line #L216 was not covered by tests
$this->scalars[] = $scalar;
}
$name = trim($name, '$');
Expand All @@ -213,7 +223,7 @@
$properties = implode("\n", $properties);
$this->states[$realName] = $properties;

return "";
return '';

Check warning on line 226 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L226

Added line #L226 was not covered by tests
}

return '';
Expand All @@ -222,30 +232,30 @@

$methods = [];

foreach($parsed->methods as $method) {
foreach ($parsed->methods as $method) {

Check warning on line 235 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L235

Added line #L235 was not covered by tests
$originalMethodName = $method['name'];
$method['name'] = ucfirst($method['name']);

$arguments = ['id: ID!'];
$method['args'] = array_map(fn(array $args) => ['type' => 'mixed', ...$args], $method['args']);

foreach($method['args'] as ['type' => $type, 'name' => $name]) {
foreach ($method['args'] as ['type' => $type, 'name' => $name]) {

Check warning on line 242 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L242

Added line #L242 was not covered by tests
[$type, $scalar] = $this->extractScalars($type);
if($scalar) {
if ($scalar) {

Check warning on line 244 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L244

Added line #L244 was not covered by tests
$this->scalars[] = $scalar;
}
$name = trim($name, '$');

$arguments[] = "$name: $type";
}
$arguments = implode(", ", $arguments);
$arguments = implode(', ', $arguments);

Check warning on line 251 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L251

Added line #L251 was not covered by tests

/*
[$returnType, $scalar] = $this->extractScalars($method['return']);
if($scalar) {
$this->scalars[] = $scalar;
}*/
$returnType = "Void!";
$returnType = 'Void!';

Check warning on line 258 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L258

Added line #L258 was not covered by tests

$methods[] = "Signal{$className}With{$method['name']}($arguments): $returnType";
$this->handlers['mutations'][] = ['op' => 'SendEntitySignal', 'op-name' => "Signal{$className}With{$method['name']}", 'realName' => $realName, 'method' => $originalMethodName];
Expand All @@ -260,7 +270,7 @@
$scalar = null;
$nullable = false;

if(str_contains($type, '|')) {
if (str_contains($type, '|')) {

Check warning on line 273 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L273

Added line #L273 was not covered by tests
if (substr_count($type, '|') === 1 && (str_contains($type, '|null') || str_contains($type, 'null|'))) {
$nullable = true;
$type = str_replace(['|null', 'null|'], '', $type);
Expand All @@ -269,19 +279,19 @@
}
}

if(str_contains($type, '?')) {
if (str_contains($type, '?')) {

Check warning on line 282 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L282

Added line #L282 was not covered by tests
$nullable = true;
$type = str_replace('?', '', $type);
}

switch($type) {
switch ($type) {
case 'string':
case 'int':
case 'float':
$type = ucfirst($type);
break;
case 'bool':
$type = "Boolean";
$type = 'Boolean';

Check warning on line 294 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L294

Added line #L294 was not covered by tests
break;
case 'EntityId':
case EntityId::class:
Expand All @@ -291,9 +301,9 @@
case OrchestrationInstance::class:
$type = 'OrchestrationId';
break;
case \DateTime::class:
case \DateTimeImmutable::class:
case \DateTimeInterface::class:
case DateTime::class:
case DateTimeImmutable::class:
case DateTimeInterface::class:

Check warning on line 306 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L304-L306

Added lines #L304 - L306 were not covered by tests
$type = 'Date';
$scalar = 'Date';
break;
Expand Down Expand Up @@ -326,7 +336,7 @@
} elseif ($class instanceof CreateDefinitionHelper) {
$class = $class->getDefinition('none')->getClassName();
}
if ($class === $parsedName && !in_array($name, $matches, true)) {
if ($class === $parsedName && ! in_array($name, $matches, true)) {

Check warning on line 339 in src/Gateway/Graph/SchemaGenerator.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/SchemaGenerator.php#L339

Added line #L339 was not covered by tests
// we have an alias
return $this->findRootName($name, $matches);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Gateway/Graph/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@
$oargs = $args;
unset($args['id']);

return getEntitySnapshot(['id' => ['id' => $oargs['id'], 'name' => $resolveInfo->fieldName], ...$args], $context);
return getEntitySnapshot(['id' => ['id' => $oargs['id'], 'name' => $handler['realName']], ...$args], $context);

Check warning on line 199 in src/Gateway/Graph/index.php

View check run for this annotation

Codecov / codecov/patch

src/Gateway/Graph/index.php#L199

Added line #L199 was not covered by tests
case 'OrchestrationStatus':
$oargs = $args;
unset($args['id']);
Expand Down
1 change: 1 addition & 0 deletions src/Glue/glue.php
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@

$permissions = json_encode($permissions, JSON_THROW_ON_ERROR);
header("Permissions: $permissions");
echo $permissions;

Check warning on line 324 in src/Glue/glue.php

View check run for this annotation

Codecov / codecov/patch

src/Glue/glue.php#L324

Added line #L324 was not covered by tests
}

private function getFromDefinition(Definition $definition): ReflectionClass|ReflectionFunction|null
Expand Down
Loading
Loading