{ "kind": "open-flow-workflow", "version": 1, "name": "Send ISS Position to Amazon SQS", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_deeb89e80142d36c": { "name": "Every minute", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "* * * * *", "timezone": "UTC" } ] }, "n_b140b22ead4f5c92": { "inputs": {}, "name": "Prepare the position URL", "kind": "task", "task": { "inputs": [], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" } ], "name": "Prepare the position URL", "moduleId": "n_92bf9db53cc1e025", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_ac5ddf822d94f0be": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_b140b22ead4f5c92", "output": "url" } ] } }, "name": "Get the ISS position", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Get the ISS position", "executor": { "method": "GET", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "none", "authentication": { "type": "none" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_fe058c8ef61872e4": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ac5ddf822d94f0be", "output": "body" } ] } }, "name": "Prepare the position message", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "message" } ], "name": "Prepare the position message", "moduleId": "n_7dede0bda6fbbe9a", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_0a26c007b5bfe577": { "inputs": { "queueUrl": { "kind": "value", "value": "YOUR_QUEUE_URL" }, "message": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_fe058c8ef61872e4", "output": "message" } ] }, "accessKeyId": { "kind": "unset" }, "secretAccessKey": { "kind": "unset" }, "sessionToken": { "kind": "value", "value": null } }, "name": "Sign the SQS request", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "queueUrl" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "message" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "accessKeyId" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "secretAccessKey" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "sessionToken" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "authorization" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "amzDate" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "body" } ], "name": "Sign the SQS request", "moduleId": "n_2cabad9f8fc1403a", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_dd4d7eee9a116cb8": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0a26c007b5bfe577", "output": "url" } ] }, "header.Content-Type": { "kind": "value", "value": "application/x-www-form-urlencoded" }, "header.Authorization": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0a26c007b5bfe577", "output": "authorization" } ] }, "header.X-Amz-Date": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0a26c007b5bfe577", "output": "amzDate" } ] }, "header.X-Amz-Security-Token": { "kind": "value", "value": null }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0a26c007b5bfe577", "output": "body" } ] } }, "name": "Send to the queue", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.Content-Type" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.Authorization" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.X-Amz-Date" }, { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "header.X-Amz-Security-Token" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Send to the queue", "executor": { "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [ "Content-Type", "Authorization", "X-Amz-Date", "X-Amz-Security-Token" ] }, "bodyFormat": "text", "authentication": { "type": "none" }, "responseFormat": "text", "statusPolicy": "success", "kind": "http-request" } } }, "n_96c7a2c1990eafe2": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd4d7eee9a116cb8", "output": "body" } ] } }, "name": "Confirm the message ID", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "messageId" } ], "name": "Confirm the message ID", "moduleId": "n_23bd3f892bfb5a3a", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_8e54c048d42ea915": { "name": "Return the message ID", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "messageId" } ], "outputMappings": { "messageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_96c7a2c1990eafe2", "output": "messageId" } ] } } } }, "edges": [ { "source": "n_deeb89e80142d36c", "target": "n_b140b22ead4f5c92" }, { "source": "n_b140b22ead4f5c92", "target": "n_ac5ddf822d94f0be" }, { "source": "n_ac5ddf822d94f0be", "target": "n_fe058c8ef61872e4" }, { "source": "n_fe058c8ef61872e4", "target": "n_0a26c007b5bfe577" }, { "source": "n_0a26c007b5bfe577", "target": "n_dd4d7eee9a116cb8" }, { "source": "n_dd4d7eee9a116cb8", "target": "n_96c7a2c1990eafe2" }, { "source": "n_96c7a2c1990eafe2", "target": "n_8e54c048d42ea915" } ] } }, "modules": { "n_92bf9db53cc1e025": { "name": "Prepare the position URL", "imports": [], "source": "export default function () {\n return {url:'https://api.wheretheiss.at/v1/satellites/25544/positions?timestamps='+Math.floor(Date.now()/1000)};\n}\n" }, "n_7dede0bda6fbbe9a": { "name": "Prepare the position message", "imports": [], "source": "export default function position({body}){const p=Array.isArray(body)?body[0]:null;if(!p||typeof p.name!=='string'||!Number.isFinite(p.latitude)||!Number.isFinite(p.longitude)||!Number.isFinite(p.timestamp))throw Error('Invalid ISS position');return{message:JSON.stringify({Name:p.name,Latitude:p.latitude,Longitude:p.longitude,Timestamp:p.timestamp})};}\n" }, "n_2cabad9f8fc1403a": { "name": "Sign the SQS request", "imports": [], "source": "import{createHash,createHmac}from'node:crypto';export default function sign({queueUrl,message,accessKeyId,secretAccessKey,sessionToken}){const m=/^https:\\/\\/sqs\\.([a-z0-9-]+)\\.amazonaws\\.com(\\.cn)?\\/(\\d{12})\\/([A-Za-z0-9_-]{1,80})$/.exec(queueUrl??'');if(!m)throw Error('Configure a standard SQS queue URL');if(typeof message!=='string'||!message||typeof accessKeyId!=='string'||!accessKeyId.trim()||typeof secretAccessKey!=='string'||!secretAccessKey.trim()||(sessionToken!=null&&typeof sessionToken!=='string'))throw Error('Configure message and AWS credentials');const region=m[1],host='sqs.'+region+'.amazonaws.com'+(m[2]??''),path='/'+m[3]+'/'+m[4],enc=x=>encodeURIComponent(x).replace(/[!'()*]/g,c=>'%'+c.charCodeAt(0).toString(16).toUpperCase()),body='Action=SendMessage&Version=2012-11-05&MessageBody='+enc(message),timestamp=new Date().toISOString().replace(/[:-]|\\.\\d{3}/g,''),date=timestamp.slice(0,8),headers={'content-type':'application/x-www-form-urlencoded',host,'x-amz-date':timestamp,...(sessionToken?{'x-amz-security-token':sessionToken}:{})},names=Object.keys(headers).sort(),signed=names.join(';'),canonicalHeaders=names.map(n=>n+':'+headers[n].trim().replace(/\\s+/g,' ')+'\\n').join(''),hash=x=>createHash('sha256').update(x).digest('hex'),hmac=(k,x)=>createHmac('sha256',k).update(x).digest(),scope=date+'/'+region+'/sqs/aws4_request',canonical=['POST',path,'',canonicalHeaders,signed,hash(body)].join('\\n'),tosign=['AWS4-HMAC-SHA256',timestamp,scope,hash(canonical)].join('\\n'),key=hmac(hmac(hmac(hmac('AWS4'+secretAccessKey,date),region),'sqs'),'aws4_request'),signature=createHmac('sha256',key).update(tosign).digest('hex');return{url:queueUrl,body,authorization:'AWS4-HMAC-SHA256 Credential='+accessKeyId+'/'+scope+', SignedHeaders='+signed+', Signature='+signature,amzDate:timestamp};}\n" }, "n_23bd3f892bfb5a3a": { "name": "Confirm the message ID", "imports": [], "source": "export default function result({body}){if(typeof body!=='string')throw Error('SQS did not return XML');const m=/<(?:[A-Za-z_][\\w.-]*:)?MessageId>\\s*([A-Za-z0-9-]+)\\s*<\\/(?:[A-Za-z_][\\w.-]*:)?MessageId>/.exec(body);if(!m)throw Error('SQS did not confirm a message ID');return{messageId:m[1]};}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }