Skip to content

Commit

Permalink
Merge branch 'fix/meme-staging' into fix/electron-builder-caching
Browse files Browse the repository at this point in the history
  • Loading branch information
truemiller authored Dec 24, 2024
2 parents fac196f + 2955d79 commit 851c5c6
Show file tree
Hide file tree
Showing 13 changed files with 484 additions and 89 deletions.
58 changes: 58 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,64 @@ Update service configuration `service_config_id` with the provided template.

---

### `PATCH /api/v2/service/{service_config_id}`

Partial update service configuration `service_config_id` with the provided (partial) template.

![Partial updates](docs/images/partial_update_examples.png)

<details>
<summary>Request</summary>

```json
{
"configurations": {...},
"description": "Trader agent for omen prediction markets",
"env_variables": {...},
"hash": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me",
"image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75",
"home_chain": "gnosis",
"name": "valory/trader_omen_gnosis",
"service_version": "v0.19.0"
}
```

</details>

<details>
<summary>Response</summary>

- If the update is successful, the response contains the updated service configuration:

```json
{
"chain_configs": {...},
"description": "Trader agent for omen prediction markets",
"env_variables": {...},
"hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u",
"hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "1731490000": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me"},
"home_chain": "gnosis",
"keys": [...],
"name": "valory/trader_omen_gnosis",
"service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39",
"service_path": "/home/user/.operate/services/sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39/trader_omen_gnosis"
}

```

- If the update is not successful:

```json
{
"error": "Error message",
"traceback": "Traceback message"
}
```

</details>

---

### `POST /api/service/{service_config_id}/stop`

Stop service with service configuration `service_configuration_id`.
Expand Down
Binary file added docs/images/partial_update_examples.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions frontend/client/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export type ChainData = {
nft: string;
staking_program_id: StakingProgramId;
threshold: number;
use_mech_marketplace: true;
use_staking: true;
use_mech_marketplace: boolean;
use_staking: boolean;
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,14 +249,9 @@ const useServiceDeployment = () => {
if (service.hash !== serviceTemplate.hash) {
await ServicesService.updateService({
serviceConfigId: service.service_config_id,
stakingProgramId: selectedStakingProgramId,
// chainId: selectedAgentConfig.evmHomeChainId,
serviceTemplate,
deploy: false, // TODO: deprecated will remove
useMechMarketplace:
STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][
selectedStakingProgramId
].mechType === MechType.Marketplace,
partialServiceTemplate: {
hash: serviceTemplate.hash,
},
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from '@/hooks/useStakingContractDetails';
import { useStakingProgram } from '@/hooks/useStakingProgram';
import { ServicesService } from '@/service/Services';
import { DeepPartial } from '@/types/Util';

import { CountdownUntilMigration } from './CountdownUntilMigration';
import { CantMigrateReason, useMigrate } from './useMigrate';
Expand All @@ -45,11 +46,10 @@ export const MigrateButton = ({
const { service } = useService(serviceConfigId);
const serviceTemplate = useMemo<ServiceTemplate | undefined>(
() =>
service
? getServiceTemplate(service.hash)
: SERVICE_TEMPLATES.find(
(template) => template.agentType === selectedAgentType,
),
(service && getServiceTemplate(service.hash)) ??
SERVICE_TEMPLATES.find(
(template) => template.agentType === selectedAgentType,
),
[selectedAgentType, service],
);

Expand Down Expand Up @@ -128,23 +128,39 @@ export const MigrateButton = ({
overrideSelectedServiceStatus(MiddlewareDeploymentStatus.DEPLOYING);
goto(Pages.Main);

const serviceConfigParams = {
stakingProgramId: stakingProgramIdToMigrateTo,
serviceTemplate,
deploy: true,
useMechMarketplace:
stakingProgramIdToMigrateTo ===
StakingProgramId.PearlBetaMechMarketplace,
};

if (selectedService) {
// update service
await ServicesService.updateService({
...serviceConfigParams,
serviceConfigId,
partialServiceTemplate: {
configurations: {
...Object.entries(serviceTemplate.configurations).reduce(
(acc, [middlewareChain]) => {
acc[middlewareChain] = {
staking_program_id: stakingProgramIdToMigrateTo,
use_mech_marketplace:
stakingProgramIdToMigrateTo ===
StakingProgramId.PearlBetaMechMarketplace,
};
return acc;
},
{} as DeepPartial<typeof serviceTemplate.configurations>,
),
},
},
});
} else {
// create service if it doesn't exist

const serviceConfigParams = {
stakingProgramId: stakingProgramIdToMigrateTo,
serviceTemplate,
deploy: true,
useMechMarketplace:
stakingProgramIdToMigrateTo ===
StakingProgramId.PearlBetaMechMarketplace,
};

await ServicesService.createService(serviceConfigParams);
}

Expand Down
36 changes: 6 additions & 30 deletions frontend/service/Services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CONTENT_TYPE_JSON_UTF8 } from '@/constants/headers';
import { BACKEND_URL_V2 } from '@/constants/urls';
import { StakingProgramId } from '@/enums/StakingProgram';
import { Address } from '@/types/Address';
import { DeepPartial } from '@/types/Util';
import { asEvmChainId } from '@/utils/middlewareHelpers';

/**
Expand Down Expand Up @@ -92,44 +93,19 @@ const createService = async ({

/**
* Updates a service
* @param serviceTemplate
* @param partialServiceTemplate
* @returns Promise<Service>
*/
const updateService = async ({
deploy,
serviceTemplate,
partialServiceTemplate,
serviceConfigId,
stakingProgramId,
useMechMarketplace = false,
}: {
deploy: boolean;
serviceTemplate: ServiceTemplate;
partialServiceTemplate: DeepPartial<ServiceTemplate>;
serviceConfigId: string;
stakingProgramId: StakingProgramId;
useMechMarketplace?: boolean;
}): Promise<MiddlewareServiceResponse> =>
fetch(`${BACKEND_URL_V2}/service/${serviceConfigId}`, {
method: 'PUT',
body: JSON.stringify({
...serviceTemplate,
deploy,
configurations: {
...serviceTemplate.configurations,
// overwrite defaults with chain-specific configurations
...Object.entries(serviceTemplate.configurations).reduce(
(acc, [middlewareChain, config]) => {
acc[middlewareChain] = {
...config,
rpc: CHAIN_CONFIG[asEvmChainId(middlewareChain)].rpc,
staking_program_id: stakingProgramId,
use_mech_marketplace: useMechMarketplace,
};
return acc;
},
{} as typeof serviceTemplate.configurations,
),
},
}),
method: 'PATCH',
body: JSON.stringify({ ...partialServiceTemplate }),
headers: { ...CONTENT_TYPE_JSON_UTF8 },
}).then((response) => {
if (response.ok) {
Expand Down
4 changes: 4 additions & 0 deletions frontend/types/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ export type Optional<T> = T | undefined;

export type Maybe<T> = Nullable<Optional<T>>;

export type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

/**
* function to strip off the null or undefined types from a type by making an assertion.
* @note This function should be used if you are confident that the value will never ever be null or undefined.
Expand Down
15 changes: 13 additions & 2 deletions operate/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def pause_all_services_on_exit(signum: int, frame: t.Optional[FrameType]) -> Non
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE"],
)

def with_retries(f: t.Callable) -> t.Callable:
Expand Down Expand Up @@ -756,6 +756,7 @@ def _fn() -> None:
)

@app.put("/api/v2/service/{service_config_id}")
@app.patch("/api/v2/service/{service_config_id}")
@with_retries
async def _update_service(request: Request) -> JSONResponse:
"""Update a service."""
Expand All @@ -765,18 +766,28 @@ async def _update_service(request: Request) -> JSONResponse:
service_config_id = request.path_params["service_config_id"]
manager = operate.service_manager()

print(service_config_id)
if not manager.exists(service_config_id=service_config_id):
return service_not_found_error(service_config_id=service_config_id)

template = await request.json()
allow_different_service_public_id = template.get(
"allow_different_service_public_id", False
)

if request.method == "PUT":
partial_update = False
else:
partial_update = True

logger.info(
f"_update_service {partial_update=} {allow_different_service_public_id=}"
)

output = manager.update(
service_config_id=service_config_id,
service_template=template,
allow_different_service_public_id=allow_different_service_public_id,
partial_update=partial_update,
)

return JSONResponse(content=output.json)
Expand Down
2 changes: 1 addition & 1 deletion operate/operate_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ class EnvVariableAttributes(TypedDict):
EnvVariables = t.Dict[str, EnvVariableAttributes]


class ServiceTemplate(TypedDict):
class ServiceTemplate(TypedDict, total=False):
"""Service template."""

name: str
Expand Down
40 changes: 37 additions & 3 deletions operate/services/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,8 +585,37 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to
):
# TODO: This is possibly not a good idea: we are setting up a computed variable based on
# the value passed in the template.
db_path = service.path / "persistent_data/memeooorr.db"
cookies_path = service.path / "persistent_data/twikit_cookies.json"
db_path = (
service.path
/ "persistent_data"
/ service.env_variables["TWIKIT_USERNAME"]["value"]
/ "memeooorr.db"
)
cookies_path = (
service.path
/ "persistent_data"
/ service.env_variables["TWIKIT_USERNAME"]["value"]
/ "twikit_cookies.json"
)

# Patch: Move existing configurations to the new location
old_db_path = service.path / "persistent_data" / "memeooorr.db"
old_cookies_path = service.path / "persistent_data" / "twikit_cookies.json"

for old_path, new_path in [
(old_db_path, db_path),
(old_cookies_path, cookies_path),
]:
if old_path.exists():
self.logger.info(f"Moving {old_path} -> {new_path}")
new_path.parent.mkdir(parents=True, exist_ok=True)
try:
os.rename(old_path, new_path)
except OSError:
self.logger.info("Fallback to shutil.move")
shutil.move(str(old_path), str(new_path))
time.sleep(3)
# End patch

env_var_to_value.update(
{
Expand Down Expand Up @@ -1689,12 +1718,17 @@ def update(
service_config_id: str,
service_template: ServiceTemplate,
allow_different_service_public_id: bool = False,
partial_update: bool = True,
) -> Service:
"""Update a service."""

self.logger.info(f"Updating {service_config_id=}")
service = self.load(service_config_id=service_config_id)
service.update(service_template, allow_different_service_public_id)
service.update(
service_template=service_template,
allow_different_service_public_id=allow_different_service_public_id,
partial_update=partial_update,
)
return service

def update_all_matching(
Expand Down
Loading

0 comments on commit 851c5c6

Please sign in to comment.