Started adding web3 functionality + some bug fixes

This commit is contained in:
frikky
2021-11-05 04:12:10 +01:00
parent 15479ea0f7
commit a82716f0ee
13 changed files with 512 additions and 72 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ require (
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/h2non/filetype v1.1.1 github.com/h2non/filetype v1.1.1
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0
github.com/shuffle/shuffle-shared v0.1.28 github.com/shuffle/shuffle-shared v0.1.30
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
google.golang.org/api v0.58.0 google.golang.org/api v0.58.0
+20
View File
@@ -1003,6 +1003,24 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
} }
} }
// FIXME: This is bad, but we've had a lot of bugs with edit users, and this is the quick fix.
if userInfo.Role == "" && userInfo.ActiveOrg.Role == "" && parsedAdmin == "false" {
userInfo.Role = "admin"
userInfo.ActiveOrg.Role = "admin"
parsedAdmin = "true"
err = shuffle.SetUser(ctx, &userInfo, true)
if err != nil {
log.Printf("[WARNING] Automatically asigning user as admin to their org because they don't have a role at all failed: %s", err)
resp.WriteHeader(500)
resp.Write([]byte(`{"success": false}`))
return
} else {
log.Printf("[DEBUG] Made user %s org-admin as they didn't have any role specified", err)
}
}
returnValue := shuffle.HandleInfo{ returnValue := shuffle.HandleInfo{
Success: true, Success: true,
Username: userInfo.Username, Username: userInfo.Username,
@@ -1017,6 +1035,7 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
Expiration: expiration.Unix(), Expiration: expiration.Unix(),
}, },
}, },
EthInfo: userInfo.EthInfo,
} }
returnData, err := json.Marshal(returnValue) returnData, err := json.Marshal(returnValue)
@@ -5785,6 +5804,7 @@ func initHandlers() {
// This is a new API that validates if a key has been seen before. // This is a new API that validates if a key has been seen before.
// Not sure what the best course of action is for it. // Not sure what the best course of action is for it.
r.HandleFunc("/api/v1/environments/{key}/stop", shuffle.HandleStopExecutions).Methods("GET", "POST", "OPTIONS")
r.HandleFunc("/api/v1/orgs/{orgId}/validate_app_values", shuffle.HandleKeyValueCheck).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/orgs/{orgId}/validate_app_values", shuffle.HandleKeyValueCheck).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/orgs/{orgId}/get_cache", shuffle.HandleGetCacheKey).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/orgs/{orgId}/get_cache", shuffle.HandleGetCacheKey).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/orgs/{orgId}/set_cache", shuffle.HandleSetCacheKey).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/orgs/{orgId}/set_cache", shuffle.HandleSetCacheKey).Methods("POST", "OPTIONS")
+12 -6
View File
@@ -577,7 +577,7 @@ func handleGetWorkflowqueueConfirm(resp http.ResponseWriter, request *http.Reque
//setWorkflowqueuetest(id) //setWorkflowqueuetest(id)
ctx := context.Background() ctx := context.Background()
executionRequests, err := shuffle.GetWorkflowQueue(ctx, id) executionRequests, err := shuffle.GetWorkflowQueue(ctx, id, 100)
if err != nil { if err != nil {
log.Printf("[WARNING] (1) Failed reading body for workflowqueue: %s", err) log.Printf("[WARNING] (1) Failed reading body for workflowqueue: %s", err)
resp.WriteHeader(401) resp.WriteHeader(401)
@@ -689,7 +689,7 @@ func handleGetWorkflowqueue(resp http.ResponseWriter, request *http.Request) {
} }
} }
executionRequests, err := shuffle.GetWorkflowQueue(ctx, id) executionRequests, err := shuffle.GetWorkflowQueue(ctx, id, 100)
if err != nil { if err != nil {
// Skipping as this comes up over and over // Skipping as this comes up over and over
//log.Printf("(2) Failed reading body for workflowqueue: %s", err) //log.Printf("(2) Failed reading body for workflowqueue: %s", err)
@@ -838,7 +838,7 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "success"}`))) resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "success"}`)))
return return
} else { } else {
//log.Printf("[WARNING] Handling other execution variant: %s", err) log.Printf("[DEBUG] Handling other execution variant: %s", err)
} }
var actionResult shuffle.ActionResult var actionResult shuffle.ActionResult
@@ -962,9 +962,15 @@ func runWorkflowExecutionTransaction(ctx context.Context, attempts int64, workfl
//log.Printf("BASE LENGTH: %d", len(workflowExecution.Results)) //log.Printf("BASE LENGTH: %d", len(workflowExecution.Results))
workflowExecution, dbSave, err := shuffle.ParsedExecutionResult(ctx, *workflowExecution, actionResult, false) workflowExecution, dbSave, err := shuffle.ParsedExecutionResult(ctx, *workflowExecution, actionResult, false)
if err != nil { if err != nil {
log.Printf("[ERROR] Failed running of parsedexecution: %s", err) b, suberr := json.Marshal(actionResult)
if suberr != nil {
log.Printf("[ERROR] Failed running of parsedexecution: %s", err)
} else {
log.Printf("[ERROR] Failed running of parsedexecution: %s. Data: %s", err, string(b))
}
resp.WriteHeader(401) resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed getting execution"}`))) resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed updating execution"}`)))
return return
} }
@@ -1284,7 +1290,7 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
workflowExecution, execInfo, _, err := shuffle.PrepareWorkflowExecution(ctx, workflow, request) workflowExecution, execInfo, _, err := shuffle.PrepareWorkflowExecution(ctx, workflow, request)
if err != nil { if err != nil {
log.Printf("[WARNING] Failed in prepareExecution: %s", err) log.Printf("[WARNING] Failed in prepareExecution: %s", err)
return shuffle.WorkflowExecution{}, "", err return shuffle.WorkflowExecution{}, fmt.Sprintf("Failed preparration: %s", err), err
} }
err = imageCheckBuilder(execInfo.ImageNames) err = imageCheckBuilder(execInfo.ImageNames)
+1
View File
@@ -0,0 +1 @@
#
+2 -2
View File
@@ -16,7 +16,7 @@ services:
depends_on: depends_on:
- backend - backend
backend: backend:
#build: ./backend build: ./backend
image: ghcr.io/frikky/shuffle-backend:nightly image: ghcr.io/frikky/shuffle-backend:nightly
container_name: shuffle-backend container_name: shuffle-backend
hostname: ${BACKEND_HOSTNAME} hostname: ${BACKEND_HOSTNAME}
@@ -48,7 +48,7 @@ services:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
environment: environment:
- SHUFFLE_APP_SDK_VERSION=0.8.97 - SHUFFLE_APP_SDK_VERSION=0.8.97
- SHUFFLE_WORKER_VERSION=0.9.30 - SHUFFLE_WORKER_VERSION=0.9.25
- ORG_ID=${ORG_ID} - ORG_ID=${ORG_ID}
- ENVIRONMENT_NAME=${ENVIRONMENT_NAME} - ENVIRONMENT_NAME=${ENVIRONMENT_NAME}
- BASE_URL=http://${OUTER_HOSTNAME}:${BACKEND_PORT} - BASE_URL=http://${OUTER_HOSTNAME}:${BACKEND_PORT}
+4 -3
View File
@@ -11,6 +11,7 @@
"@material-ui/lab": "^4.0.0-alpha.58", "@material-ui/lab": "^4.0.0-alpha.58",
"@material-ui/styles": "^4.5.2", "@material-ui/styles": "^4.5.2",
"@material-ui/utils": "^4.11.2", "@material-ui/utils": "^4.11.2",
"@metamask/detect-provider": "^1.2.0",
"@uiw/react-codemirror": "^3.2.1", "@uiw/react-codemirror": "^3.2.1",
"@use-it/interval": "^1.0.0", "@use-it/interval": "^1.0.0",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
@@ -79,9 +80,9 @@
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app", "extends": "react-app",
"rules":{ "rules": {
"jsx-a11y/img-redundant-alt" : "off", "jsx-a11y/img-redundant-alt": "off",
"no-redeclare" : "off", "no-redeclare": "off",
"no-loop-func": "off" "no-loop-func": "off"
} }
}, },
+102 -3
View File
@@ -38,6 +38,8 @@ import AlertTemplate from "./components/AlertTemplate";
import { positions, Provider } from "react-alert"; import { positions, Provider } from "react-alert";
import {isMobile} from "react-device-detect"; import {isMobile} from "react-device-detect";
import detectEthereumProvider from '@metamask/detect-provider';
// Production - backend proxy forwarding in nginx // Production - backend proxy forwarding in nginx
var globalUrl = window.location.origin var globalUrl = window.location.origin
@@ -97,18 +99,113 @@ const App = (message, props) => {
}) })
.then(response => response.json()) .then(response => response.json())
.then(responseJson => { .then(responseJson => {
var userInfo = {}
if (responseJson.success === true) { if (responseJson.success === true) {
console.log(responseJson) console.log(responseJson)
setUserData(responseJson)
userInfo = responseJson
setIsLoggedIn(true) setIsLoggedIn(true)
//console.log("Cookies: ", cookies) //console.log("Cookies: ", cookies)
// Updating cookie every request // Updating cookie every request
for (var key in responseJson["cookies"]) { for (var key in responseJson["cookies"]) {
setCookie(responseJson["cookies"][key].key, responseJson["cookies"][key].value, { path: "/" }) setCookie(responseJson["cookies"][key].key, responseJson["cookies"][key].value, { path: "/" })
} }
} }
// Handling Ethereum update
detectEthereumProvider()
.then((provider) => {
if (provider) {
if (userInfo.eth_info.account !== undefined && userInfo.eth_info.account !== null && userInfo.eth_info.account.length === 0) {
userInfo.eth_info = {}
var method = "eth_requestAccounts"
var params = []
provider.request({
method: method,
params,
})
.then((result) => {
if (result !== undefined && result !== null && result.length > 0) {
userInfo.eth_info.account = result[0]
// Getting and setting balance for the current user
method = "eth_getBalance"
params = [
userInfo.eth_info.account,
"latest"
]
provider.request({
method: method,
params,
})
.then((result) => {
if (result !== undefined && result !== null && result.length > 0) {
userInfo.parsed_balance = result/1000000000000000000
} else {
alert.error("Couldn't find balance: ", result)
}
// The result varies by RPC method.
// For example, this method will return a transaction hash hexadecimal string on success.
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error("Failed getting info from ethereum API: "+error)
})
} else {
alert.error("Couldn't find any user: ", result)
}
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error("Failed getting info from ethereum API: "+error)
})
}
// Register hooks here
provider.on('message', (event) => {
alert.info("Message from MetaMask: ", event)
})
provider.on('chainChanged', (chainId) => {
console.log("Changed chain to: ", chainId)
method = "eth_getBalance"
params = [
userInfo.eth_info.account,
"latest"
]
provider.request({
method: method,
params,
})
.then((result) => {
console.log("Got result: ", result)
if (result !== undefined && result !== null) {
userInfo.eth_info.balance = result
userInfo.eth_info.parsed_balance = result/1000000000000000000
console.log("INFO: ", userInfo)
setUserData(userInfo)
} else {
alert.error("Couldn't find balance: ", result)
}
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error("Failed getting info from ethereum API: "+error)
})
})
}
})
if (userInfo.eth_info !== undefined && userInfo.eth_info.balance !== undefined) {
console.log(userInfo.eth_info.balance)
userInfo.eth_info.parsed_balance = userInfo.eth_info.balance/1000000000000000000
}
console.log("USER: ", userInfo)
setUserData(userInfo)
setIsLoaded(true) setIsLoaded(true)
}) })
.catch(error => { .catch(error => {
setIsLoaded(true) setIsLoaded(true)
@@ -133,7 +230,9 @@ const App = (message, props) => {
<Route exact path="/login" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} checkLogin={checkLogin} {...props} />} /> <Route exact path="/login" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} checkLogin={checkLogin} {...props} />} />
<Route exact path="/admin" render={props => <Admin userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} /> <Route exact path="/admin" render={props => <Admin userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
<Route exact path="/admin/:key" render={props => <Admin isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} /> <Route exact path="/admin/:key" render={props => <Admin isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
<Route exact path="/settings" render={props => <SettingsPage isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} /> {userdata.id !== undefined ?
<Route exact path="/settings" render={props => <SettingsPage isLoaded={isLoaded} setUserData={setUserData} userdata={userdata} globalUrl={globalUrl} {...props} />} />
: null}
<Route exact path="/AdminSetup" render={props => <AdminSetup isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} /> <Route exact path="/AdminSetup" render={props => <AdminSetup isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} />
<Route exact path="/webhooks" render={props => <Webhooks isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} /> <Route exact path="/webhooks" render={props => <Webhooks isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
<Route exact path="/webhooks/:key" render={props => <EditWebhook isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} /> <Route exact path="/webhooks/:key" render={props => <EditWebhook isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
+39 -3
View File
@@ -685,6 +685,31 @@ const Admin = (props) => {
}) })
} }
const abortEnvironmentWorkflows = (environment) => {
console.log("Aborting all workflows started >10 minutes ago, not finished")
fetch(`${globalUrl}/api/v1/environments/${environment}/stop`, {
method: 'GET',
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for apps :O!")
return
}
return response.json()
})
.then((responseJson) => {
console.log("Got response for execution: ", responseJson)
//console.log("RESPONSE: ", responseJson)
//setFiles(responseJson)
})
.catch(error => {
//alert.error(error.toString())
})
}
const deleteEnvironment = (environment) => { const deleteEnvironment = (environment) => {
// FIXME - add some check here ROFL // FIXME - add some check here ROFL
//const name = environment.name //const name = environment.name
@@ -1375,6 +1400,7 @@ const Admin = (props) => {
style={{ maxHeight: 50, flex: 1 }} style={{ maxHeight: 50, flex: 1 }}
variant="outlined" variant="outlined"
color="primary" color="primary"
disabled={selectedUser.role === "admin"}
onClick={() => { onClick={() => {
setUser(selectedUser.id, "username", newUsername) setUser(selectedUser.id, "username", newUsername)
}} }}
@@ -1410,6 +1436,7 @@ const Admin = (props) => {
style={{ maxHeight: 50, flex: 1 }} style={{ maxHeight: 50, flex: 1 }}
variant="outlined" variant="outlined"
color="primary" color="primary"
disabled={selectedUser.role === "admin"}
onClick={() => onPasswordChange()} onClick={() => onPasswordChange()}
> >
Submit Submit
@@ -1421,6 +1448,7 @@ const Admin = (props) => {
style={{}} style={{}}
variant="outlined" variant="outlined"
color="primary" color="primary"
disabled={selectedUser.role === "admin"}
onClick={() => deleteUser(selectedUser)} onClick={() => deleteUser(selectedUser)}
> >
{selectedUser.active ? "Deactivate" : "Activate"} {selectedUser.active ? "Deactivate" : "Activate"}
@@ -1429,6 +1457,7 @@ const Admin = (props) => {
style={{}} style={{}}
variant="outlined" variant="outlined"
color="primary" color="primary"
disabled={selectedUser.role === "admin" && selectedUser.username !== userdata.username}
onClick={() => generateApikey(selectedUser)} onClick={() => generateApikey(selectedUser)}
> >
Get new API key Get new API key
@@ -2148,6 +2177,7 @@ const Admin = (props) => {
onClick={() => { onClick={() => {
generateApikey(data) generateApikey(data)
}} }}
disabled={data.role === "admin" && data.username !== userdata.username}
variant="outlined" variant="outlined"
color="primary" color="primary"
> >
@@ -2777,14 +2807,20 @@ const Admin = (props) => {
{environment.default ? {environment.default ?
null null
: :
<Button variant="outlined" style={{borderRadius: "0px"}} onClick={() => setDefaultEnvironment(environment)} color="primary">Set default</Button> <Button variant="outlined" style={{borderRadius: "0px"}} onClick={() => setDefaultEnvironment(environment)} color="primary">Make default</Button>
} }
</ListItemText> </ListItemText>
<ListItemText <ListItemText
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}} style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
> >
<Button variant={environment.archived ? "contained" : "outlined"} style={{borderRadius: "0px"}} onClick={() => deleteEnvironment(environment)} color="primary">{environment.archived ? "Activate" : "Disable"}</Button> <div style={{display: "flex"}}>
{/*<Button disabled={environment.archived} variant="outlined" style={{borderRadius: "0px"}} onClick={() => flushQueue(environment.Name)} color="primary">Flush Queue</Button>*/} <Button variant={environment.archived ? "contained" : "outlined"} style={{borderRadius: "0px"}} onClick={() => deleteEnvironment(environment)} color="primary">{environment.archived ? "Activate" : "Disable"}</Button>
{/*<Button variant={environment.archived ? "contained" : "outlined"} style={{borderRadius: "0px"}} onClick={() => {
console.log("Should clear executions")
abortEnvironmentWorkflows(environment)
}} color="primary">Clear executions</Button>*/}
{/*<Button disabled={environment.archived} variant="outlined" style={{borderRadius: "0px"}} onClick={() => flushQueue(environment.Name)} color="primary">Flush Queue</Button>*/}
</div>
</ListItemText> </ListItemText>
<ListItemText <ListItemText
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}} style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
+5 -6
View File
@@ -417,10 +417,10 @@ const Apps = (props) => {
} }
}}> }}>
<Grid container style={{margin: 10, flex: "10", maxHeight: 110, overflow: "hidden",}}> <Grid container style={{margin: 10, flex: "10", maxHeight: 110, overflow: "hidden",}}>
<ButtonBase style={{backgroundColor: theme.palette.inputColor, border: 3}}> <ButtonBase style={{backgroundColor: theme.palette.surfaceColor, maxHeight:100, marginTop: 5,}}>
{imageline} {imageline}
</ButtonBase> </ButtonBase>
<div style={{marginLeft: "10px", marginTop: "5px", marginBottom: "5px", width: boxWidth, backgroundColor: boxColor}}/> <div style={{marginLeft: "10px", marginTop: 5, marginBottom: 5, width: boxWidth, backgroundColor: boxColor}}/>
<Grid container style={{margin: "0px 0px 10px 10px", flex: "1"}}> <Grid container style={{margin: "0px 0px 10px 10px", flex: "1"}}>
<Grid style={{display: "flex", flexDirection: "column", }}> <Grid style={{display: "flex", flexDirection: "column", }}>
<Grid item style={{flex: "1"}}> <Grid item style={{flex: "1"}}>
@@ -648,7 +648,7 @@ const Apps = (props) => {
var baseInfo = newAppname.length > 0 ? var baseInfo = newAppname.length > 0 ?
<div style={{position: "relative"}}> <div style={{position: "relative"}}>
<div style={{display: "flex"}}> <div style={{display: "flex"}}>
<div style={{marginRight: 15, marginTop: 10}}> <div style={{marginRight: 15, marginTop: 10, backgroundColor: theme.palette.surfaceColor,}}>
{imageline} {imageline}
</div> </div>
<div style={{maxWidth: "85%", overflow: "hidden"}}> <div style={{maxWidth: "85%", overflow: "hidden"}}>
@@ -846,7 +846,7 @@ const Apps = (props) => {
return( return(
<div style={{}}> <div style={{}}>
<Paper square style={uploadViewPaperStyle}> <Paper square style={uploadViewPaperStyle}>
<div style={{width: "100%", margin: 25}}> <div style={{margin: 25}}>
<h2>App Creator</h2> <h2>App Creator</h2>
<a rel="noopener noreferrer" href="https://shuffler.io/docs/apps" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">How it works</a> <a rel="noopener noreferrer" href="https://shuffler.io/docs/apps" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">How it works</a>
&nbsp;- <a rel="noopener noreferrer" href="https://github.com/frikky/security-openapis" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">Security API's</a> &nbsp;- <a rel="noopener noreferrer" href="https://github.com/frikky/security-openapis" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">Security API's</a>
@@ -885,7 +885,7 @@ const Apps = (props) => {
</div> </div>
</Paper> </Paper>
<Paper square style={uploadViewPaperStyle}> <Paper square style={uploadViewPaperStyle}>
<div style={{width: "100%", margin: 25}}> <div style={{margin: 25}}>
{baseInfo} {baseInfo}
</div> </div>
</Paper> </Paper>
@@ -1684,7 +1684,6 @@ const Apps = (props) => {
</Dialog> </Dialog>
: null : null
const loadedCheck = isLoaded && !firstrequest ? const loadedCheck = isLoaded && !firstrequest ?
<div> <div>
{appView} {appView}
+311 -19
View File
@@ -1,12 +1,14 @@
import React, {useState, useEffect} from 'react'; import React, {useState, useEffect} from 'react';
import {Paper, Button, Divider, TextField} from '@material-ui/core'; import {Typography, Paper, Button, Divider, TextField} from '@material-ui/core';
import {Link} from 'react-router-dom'; import {Link} from 'react-router-dom';
import { useAlert } from "react-alert"; import { useAlert } from "react-alert";
import { useTheme } from '@material-ui/core/styles'; import { useTheme } from '@material-ui/core/styles';
import detectEthereumProvider from '@metamask/detect-provider';
const Settings = (props) => { const Settings = (props) => {
const { globalUrl, isLoaded, userdata, } = props; const { globalUrl, isLoaded, userdata, setUserData } = props;
const theme = useTheme(); const theme = useTheme();
const alert = useAlert() const alert = useAlert()
@@ -29,8 +31,36 @@ const Settings = (props) => {
const [firstrequest, setFirstRequest] = useState(true) const [firstrequest, setFirstRequest] = useState(true)
const [userInfo, ] = useState(userdata)
const [userSettings, setUserSettings] = useState({}) const [userSettings, setUserSettings] = useState({})
console.log(userdata)
/*
const [userdata.eth_info, setEthInfo] = useState(userdata.eth_info !== undefined && userdata.eth_info.account !== undefined && userdata.eth_info.account.length > 0 ? userdata.eth_info : {
"account": "",
"balance": "",
})
*/
/*
console.log(userdata.eth_info)
if (userdata.eth_info.account.length === 0 && userdata.eth_info !== undefined && userdata.eth_info.account !== undefined && userdata.eth_info.account.length > 0) {
setEthInfo(userdata.eth_info)
} else if (userdata.eth_info.balance.length > 0 && userdata.eth_info.parsed_balance === undefined) {
//console.log(window.ethereum)
//console.log(window.ethereum.utils.formatEther(userdata.eth_info.balance))
const parsed_balance = parseInt(userdata.eth_info.balance, 16)/1000000000000000000
console.log("Parsed balance: ", parsed_balance)
userdata.eth_info.parsed_balance = parsed_balance
userdata.eth_info.parsed_balance = parsed_balance
setEthInfo(userdata.eth_info)
} else if (userdata.eth_info !== undefined && userdata.eth_info.balance !== userdata.eth_info.balance) {
console.log("Updating balance: ", userdata.eth_info)
setEthInfo(userdata.eth_info)
}
*/
//Returns the value from a storage position at a given address.
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
const bodyDivStyle = { const bodyDivStyle = {
@@ -133,39 +163,97 @@ const Settings = (props) => {
// Gotta be a better way of doing this rofl // Gotta be a better way of doing this rofl
const setFields = () => { const setFields = () => {
if (userInfo.username !== undefined) { if (userdata.username !== undefined) {
if (userInfo.username.length > 0) { if (userdata.username.length > 0) {
setUsername(userInfo.username) setUsername(userdata.username)
} }
//if (userInfo.firstname.length > 0) { //if (userdata.firstname.length > 0) {
// setFirstname(userInfo.firstname) // setFirstname(userdata.firstname)
//} //}
//if (userInfo.lastname.length > 0) { //if (userdata.lastname.length > 0) {
// setLastname(userInfo.lastname) // setLastname(userdata.lastname)
//} //}
//if (userInfo.title.length > 0) { //if (userdata.title.length > 0) {
// setTitle(userInfo.title) // setTitle(userdata.title)
//} //}
//if (userInfo.companyname.length > 0) { //if (userdata.companyname.length > 0) {
// setCompanyname(userInfo.companyname) // setCompanyname(userdata.companyname)
//} //}
//if (userInfo.phone.length > 0) { //if (userdata.phone.length > 0) {
// setPhone(userInfo.phone) // setPhone(userdata.phone)
//} //}
//if (userInfo.email.length > 0) { //if (userdata.email.length > 0) {
// setEmail(userInfo.email) // setEmail(userdata.email)
//} //}
} }
} }
const registerProviders = (userdata) => {
// Register hooks here
detectEthereumProvider()
.then((provider) => {
if (provider) {
if (!provider.isMetaMask) {
alert.error("Only MetaMask is supported as of now.")
return
}
// Find the ethereum network
// Get the users' account(s)
//alert.info("Connecting to MetaMask")
//console.log("Connected: ", provider.isConnected())
if (!provider.isConnected()) {
alert.error("Metamask is not connected.")
return
}
provider.on('message', (event) => {
alert.info("Ethereum message: ", event)
})
provider.on('chainChanged', (chainId) => {
console.log("Changed chain to: ", chainId)
const method = "eth_getBalance"
const params = [
userdata.eth_info.account,
"latest"
]
provider.request({
method: method,
params,
})
.then((result) => {
console.log("Got result: ", result)
if (result !== undefined && result !== null) {
userdata.eth_info.balance = result
userdata.eth_info.parsed_balance = result/1000000000000000000
console.log("INFO: ", userdata)
setUserData(userdata)
} else {
alert.error("Couldn't find balance: ", result)
}
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error("Failed getting info from ethereum API: "+error)
})
})
}
})
}
// This should "always" have data // This should "always" have data
useEffect(() => { useEffect(() => {
if (firstrequest) { if (firstrequest) {
setFirstRequest(false) setFirstRequest(false)
getSettings() getSettings()
//registerProviders(userdata)
} }
if (Object.getOwnPropertyNames(userInfo).length > 0 && (username === "" && email === "")) { if (Object.getOwnPropertyNames(userdata).length > 0 && (username === "" && email === "")) {
setFields() setFields()
} }
}) })
@@ -440,9 +528,213 @@ const Settings = (props) => {
Submit password change Submit password change
</Button> </Button>
<h3>{passwordFormMessage}</h3> <h3>{passwordFormMessage}</h3>
<Divider style={{marginTop: "40px"}}/>
{userdata !== undefined && userdata.eth_info !== undefined && userdata.eth_info.account.length > 0 ?
<Button
style={{height: 40, marginTop: 10}}
variant="contained"
color="primary"
fullWidth={true}
onClick={() => {
handleEthereumTokenCreation()
}}
>
Create token
</Button>
:
<Button
style={{height: 40, marginTop: 10}}
variant="outlined"
color="primary"
fullWidth={true}
onClick={() => {
handleEthereumConnection()
}}
>
Authenticate
</Button>
}
{userdata.eth_info !== undefined && userdata.eth_info.account !== undefined && userdata.eth_info.account.length > 0 && userdata.eth_info.parsed_balance !== undefined ?
<div style={{marginTop: 10, display: "flex",}}>
<Paper square style={{borderRadius: theme.palette.borderRadius, padding: 50, backgroundColor: theme.palette.inputColor}}>
<Typography>
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Ethereum-icon-purple.svg/480px-Ethereum-icon-purple.svg.png" style={{height: 30 }}/>
</Typography>
<Typography>
{/*window.ethereum.fromWei(userdata.eth_info.balance, "ether")*/}
{userdata.eth_info.parsed_balance.toFixed(4)} ETH
</Typography>
</Paper>
</div>
: null}
</Paper> </Paper>
</div> </div>
/*
0x1 1 Ethereum Main Network (Mainnet)
0x3 3 Ropsten Test Network
0x4 4 Rinkeby Test Network
0x5 5 Goerli Test Network
0x2a 42 Kovan Test Network
*/
const setUser = (userId, field, value) => {
const data = { "user_id": userId }
data[field] = value
fetch(globalUrl + "/api/v1/users/updateuser", {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify(data),
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
}
return response.json()
})
.then((responseJson) => {
if (!responseJson.success && responseJson.reason !== undefined) {
alert.error("Failed updating user: " + responseJson.reason)
}
})
.catch(error => {
console.log(error)
});
}
const handleEthereumTokenCreation = async () => {
const provider = await detectEthereumProvider();
if (!provider) {
console.log('Please install MetaMask!');
alert.error("Please download the MetaMask browser extension to authenticate fully!")
return
}
if (!provider.isMetaMask) {
alert.error("Only MetaMask is supported as of now.")
return
}
if (!provider.isConnected()) {
alert.error("Metamask is not connected.")
return
}
console.log("Should make a token")
}
const handleEthereumConnection = async () => {
const provider = await detectEthereumProvider();
if (!provider) {
console.log('Please install MetaMask!');
alert.error("Please download the MetaMask browser extension to authenticate fully!")
return
}
if (!provider.isMetaMask) {
alert.error("Only MetaMask is supported as of now.")
return
}
// Find the ethereum network
// Get the users' account(s)
//alert.info("Connecting to MetaMask")
//console.log("Connected: ", provider.isConnected())
if (!provider.isConnected()) {
alert.error("Metamask is not connected.")
return
}
provider.on('message', (event) => {
alert.info("Ethereum message: ", event)
})
/*
params: [
{
from: '0xb60e8dd61c5d32be8058bb8eb970870f07233155',
to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
gas: '0x76c0', // 30400
gasPrice: '0x9184e72a000', // 10000000000000
value: '0x9184e72a', // 2441406250
data:
'0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675',
},
]
*/
// https://docs.metamask.io/guide/rpc-api.html
// Gets accounts - requires previous permissions
//const method = "eth_accounts"
//const params = []
//
// Asks for permission, and gets the accounts
var method = "eth_requestAccounts"
var params = []
provider.request({
method: method,
params,
})
.then((result) => {
if (result !== undefined && result !== null && result.length > 0) {
userdata.eth_info.account = result[0]
// Getting and setting balance for the current user
method = "eth_getBalance"
params = [
userdata.eth_info.account,
"latest"
]
provider.request({
method: method,
params,
})
.then((result) => {
if (result !== undefined && result !== null && result.length > 0) {
userdata.eth_info.balance = result
userdata.eth_info.parsed_balance = result/1000000000000000000
console.log(userdata.eth_info)
setUserData(userdata.eth_info)
// Updating
//if (userdata.eth_info !== userdata.userdata.eth_info) {
//}
setUser(userdata.id, "eth_info", userdata.eth_info)
userdata.userdata.eth_info = userdata.eth_info
} else {
alert.error("Couldn't find balance: ", result)
}
// The result varies by RPC method.
// For example, this method will return a transaction hash hexadecimal string on success.
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
//setEthInfo(userdata.eth_info)
alert.error("Failed getting info from ethereum API: "+error)
})
} else {
alert.error("Couldn't find any user: ", result)
}
})
.catch((error) => {
// If the request fails, the Promise will reject with an error.
alert.error("Failed getting info from ethereum API: "+error)
})
// Gets the users' balance in WEI (one quintilionth ETH)
}
const loadedCheck = isLoaded && !firstrequest ? const loadedCheck = isLoaded && !firstrequest ?
<div style={bodyDivStyle}> <div style={bodyDivStyle}>
{landingpageData} {landingpageData}
+2 -2
View File
@@ -646,7 +646,7 @@ const Workflows = (props) => {
for (var key in responseJson) { for (var key in responseJson) {
for (var actionkey in responseJson[key].actions) { for (var actionkey in responseJson[key].actions) {
const action = responseJson[key].actions[actionkey] const action = responseJson[key].actions[actionkey]
console.log("Action: ", action) //console.log("Action: ", action)
if (actionnamelist.includes(action.app_name)) { if (actionnamelist.includes(action.app_name)) {
continue continue
} }
@@ -656,7 +656,7 @@ const Workflows = (props) => {
} }
} }
console.log(parsedactionlist) //console.log(parsedactionlist)
setActionImageList(parsedactionlist) setActionImageList(parsedactionlist)
} }
+1
View File
@@ -217,6 +217,7 @@ func deployServiceWorkers(image string) {
Image: image, Image: image,
Env: []string{ Env: []string{
fmt.Sprintf("SHUFFLE_SWARM_CONFIG=%s", os.Getenv("SHUFFLE_SWARM_CONFIG")), fmt.Sprintf("SHUFFLE_SWARM_CONFIG=%s", os.Getenv("SHUFFLE_SWARM_CONFIG")),
fmt.Sprintf("SHUFFLE_SWARM_NETWORK_NAME=%s", networkName),
}, },
Mounts: []mount.Mount{ Mounts: []mount.Mount{
mount.Mount{ mount.Mount{
+12 -27
View File
@@ -117,11 +117,11 @@ func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason
} }
*/ */
} else { } else {
log.Printf("[INFO] NOT cleaning up containers. IDS: %d, CLEANUP env: %s", len(containerIds), cleanupEnv) log.Printf("[DEBUG] NOT cleaning up containers. IDS: %d, CLEANUP env: %s", len(containerIds), cleanupEnv)
} }
if len(reason) > 0 && len(nodeId) > 0 { if len(reason) > 0 && len(nodeId) > 0 {
log.Printf("[INFO] Running abort of workflow because it should be finished") //log.Printf("[INFO] Running abort of workflow because it should be finished")
abortUrl := fmt.Sprintf("%s/api/v1/workflows/%s/executions/%s/abort", baseUrl, workflowExecution.Workflow.ID, workflowExecution.ExecutionId) abortUrl := fmt.Sprintf("%s/api/v1/workflows/%s/executions/%s/abort", baseUrl, workflowExecution.Workflow.ID, workflowExecution.ExecutionId)
path := fmt.Sprintf("?reason=%s", url.QueryEscape(reason)) path := fmt.Sprintf("?reason=%s", url.QueryEscape(reason))
@@ -134,7 +134,7 @@ func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason
//fmt.Println(url.QueryEscape(query)) //fmt.Println(url.QueryEscape(query))
abortUrl += path abortUrl += path
log.Printf("[INFO] Abort URL: %s", abortUrl) log.Printf("[DEBUG] Abort URL: %s", abortUrl)
req, err := http.NewRequest( req, err := http.NewRequest(
"GET", "GET",
@@ -178,7 +178,7 @@ func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason
} }
} }
log.Printf("[INFO] All App Logs: %#v", allLogs) log.Printf("[DEBUG] All App Logs: %#v", allLogs)
_, err = client.Do(req) _, err = client.Do(req)
if err != nil { if err != nil {
log.Printf("[WARNING] Failed abort request: %s", err) log.Printf("[WARNING] Failed abort request: %s", err)
@@ -301,7 +301,7 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
}) })
} }
} else { } else {
log.Printf("[WARNING] Not mounting folders") //log.Printf("[WARNING] Not mounting folders")
} }
config := &container.Config{ config := &container.Config{
@@ -397,7 +397,7 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
//log.Printf("[INFO] Info for container: %#v", stats) //log.Printf("[INFO] Info for container: %#v", stats)
//log.Printf("%#v", stats.Config) //log.Printf("%#v", stats.Config)
//log.Printf("%#v", stats.ContainerJSONBase.State) //log.Printf("%#v", stats.ContainerJSONBase.State)
log.Printf("[INFO] EXECUTION STATUS: %s", stats.ContainerJSONBase.State.Status) log.Printf("[DEBUG] EXECUTION STATUS: %s", stats.ContainerJSONBase.State.Status)
logOptions := types.ContainerLogsOptions{ logOptions := types.ContainerLogsOptions{
ShowStdout: true, ShowStdout: true,
} }
@@ -1352,7 +1352,7 @@ func executionInit(workflowExecution shuffle.WorkflowExecution) error {
// Setting up extra counter // Setting up extra counter
for _, trigger := range workflowExecution.Workflow.Triggers { for _, trigger := range workflowExecution.Workflow.Triggers {
//log.Printf("Appname trigger (0): %s", trigger.AppName) log.Printf("[DEBUG] Appname trigger (0): %s", trigger.AppName)
if trigger.AppName == "User Input" || trigger.AppName == "Shuffle Workflow" { if trigger.AppName == "User Input" || trigger.AppName == "Shuffle Workflow" {
extra += 1 extra += 1
} }
@@ -2717,28 +2717,13 @@ func main() {
//wg.Wait() //wg.Wait()
} else { } else {
log.Printf("\n\n[INFO] Running NON-OPTIMIZED execution for type %s with %d environment(s). This only happens when ran manually OR when running with subflows. Status: %s\n\n", workflowExecution.ExecutionSource, len(environments), workflowExecution.Status) log.Printf("\n\n[INFO] Running NON-OPTIMIZED execution for type %s with %d environment(s). This only happens when ran manually OR when running with subflows. Status: %s\n\n", workflowExecution.ExecutionSource, len(environments), workflowExecution.Status)
//err := executionInit(workflowExecution) err := executionInit(workflowExecution)
//if err != nil { if err != nil {
// log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err) log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
// shutdown(workflowExecution, "", "", true) shutdown(workflowExecution, "", "", true)
//} }
// Trying to make worker into microservice~ :) // Trying to make worker into microservice~ :)
if os.Getenv("SHUFFLE_SWARM_CONFIG") == "run" {
listener := webserverSetup(workflowExecution)
err := executionInit(workflowExecution)
if err != nil {
log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
log.Printf("[DEBUG] Shutting down (30)")
shutdown(workflowExecution, "", "", true)
}
go func() {
time.Sleep(time.Duration(1))
handleExecutionResult(workflowExecution)
}()
runWebserver(listener)
}
} }
} }