Skip to content

Instantly share code, notes, and snippets.

@XeroAlpha
Last active July 20, 2026 14:30
Show Gist options
  • Select an option

  • Save XeroAlpha/82ecd951f51f4877d6279afc2057033a to your computer and use it in GitHub Desktop.

Select an option

Save XeroAlpha/82ecd951f51f4877d6279afc2057033a to your computer and use it in GitHub Desktop.
Huginn API written by Node.js
// dependence: got, cheerio, tough
// haven't complete
// haven't fully tested
const got = require("got").default;
const cheerio = require("cheerio");
const tough = require("tough-cookie");
const nodeUrl = require("url");
async function fetchAsDOM(client, url) {
return cheerio.load((await client.get(url, { responseType: "text" })).body);
}
async function fetchCSRFToken(client, url) {
const dom$ = await fetchAsDOM(client, url);
return dom$("meta[name=csrf-token]").attr("content");
}
exports.login = async function(url, user, pass) {
const cookieJar = new tough.CookieJar();
const pageClient = got.extend({
prefixUrl: url,
cookieJar,
// agent: { // only for test
// http: require("tunnel").httpOverHttp({ proxy: { host: "127.0.0.1", port: 8080 } })
// }
});
const client = pageClient.extend({ responseType: "json" });
const csrfToken = await fetchCSRFToken(pageClient, "./users/sign_in");
await pageClient.post("./users/sign_in", {
json: {
"authenticity_token": csrfToken,
"user": {
"login": user,
"password": pass,
"remember_me": 0
},
"commit": "Log in"
},
followRedirect: false
});
return {
client,
pageClient,
fetchCSRFToken: fetchCSRFToken.bind(pageClient)
};
}
const pagination = {
paginate: (response, allItems, currentItems) => {
const previousSearchParams = response.request.options.searchParams || new nodeUrl.URLSearchParams();
const previousPageIndex = previousSearchParams.get("page") || 1;
const itemCountLimit = previousSearchParams.get("limit") || Infinity; // Huginn doesn't use it
if (currentItems.length == 0 || allItems.length >= itemCountLimit) {
return false;
}
return {
searchParams: {
...previousSearchParams,
page: Number(previousPageIndex) + 1
}
};
}
};
exports.Agent = {
list: async function(credential, options) {
return await credential.client.paginate.all("./agents", { searchParams: options, pagination });
},
postManualEvent: async function(credential, id, payload) {
const csrfToken = await credential.fetchCSRFToken("./agents");
return await credential.client.post(`./agents/${id}/handle_details_post`, {
json: {
authenticity_token: csrfToken,
payload
}
});
},
run: async function(credential, id) {
const csrfToken = await credential.fetchCSRFToken("./agents");
return await credential.client.post(`./agents/${id}/run`, {
json: {
authenticity_token: csrfToken
}
});
},
getTypeDetails: async function(credential, agentType) {
return await credential.client.get("./agents/type_details", { searchParams: { type: agentType } });
},
getEventDescription: async function(credential, agentIds) {
return await credential.client.get("./agents/event_descriptions", { searchParams: { ids: agentIds.json(",") } });
},
reemitEvents: async function(credential, id, deleteOldEvents) {
const csrfToken = await credential.fetchCSRFToken("./agents");
return await credential.client.post(`./agents/${id}/reemit_events`, {
json: {
authenticity_token: csrfToken,
commit: "Re-emit all events",
delete_old_events: deleteOldEvents ? 1 : 0
}
});
},
removeEvents: async function(credential, id) {
const csrfToken = await credential.fetchCSRFToken("./agents");
return await credential.client.delete(`./agents/${id}/reemit_events`, {
json: {
authenticity_token: csrfToken
}
});
},
propagateEvents: async function(credential) {
const csrfToken = await credential.fetchCSRFToken("./agents");
return await credential.client.post(`./agents/${id}/reemit_events`, {
json: {
authenticity_token: csrfToken
}
});
},
clearMemory: async function(credential, id) {
const csrfToken = await credential.fetchCSRFToken("./agents");
return await credential.client.delete(`./agents/${id}/memory`, {
json: {
authenticity_token: csrfToken
}
});
},
get: async function(credential, id) {
return await credential.client.get(`./agents/${id}`);
},
getDefault: async function(credential) {
return await credential.client.post("./agents/new");
},
create: async function(credential, data) {
const csrfToken = await credential.fetchCSRFToken("./agents");
return await credential.client.post("./agents", {
json: {
authenticity_token: csrfToken,
agent: data,
commit: "Save"
}
});
},
update: async function(credential, id, data) {
const csrfToken = await credential.fetchCSRFToken("./agents");
return await credential.client.put(`./agents/${id}`, {
json: {
authenticity_token: csrfToken,
agent: data,
commit: "Save"
}
});
},
remove: async function(credential, id) {
const csrfToken = await credential.fetchCSRFToken("./agents");
return await credential.client.delete(`./agents/${id}`, {
json: {
authenticity_token: csrfToken
}
});
}
}
exports.Scenarios = {
list: async function(credential, options) {
return await credential.client.paginate.all("./scenarios", { searchParams: options, pagination });
},
getDefault: async function(credential) {
return await credential.client.post("./scenarios/new");
},
get: async function(credential, id) {
return await credential.client.get(`./scenarios/${id}`);
}
}
exports.listEvents = async function(credential, options) {
return await credential.client.paginate.all("./events", { searchParams: options, pagination });
}
exports.listJobs = async function(credential, options) {
return await credential.client.paginate.all("./jobs", { searchParams: options, pagination });
}
exports.getWorkerStatus = async function(credential, options) {
return await credential.client.get("./worker_status", { searchParams: options });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment