Created
October 14, 2023 11:28
-
-
Save matthewgream/0515376848bbea57abc996c14eef21a9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
function code_filter_for_gcloud (v) { | |
return !v.includes ('CODE' + ':' + 'GCLOUD'); | |
} | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
/* CODE:GCLOUD | |
const { Console } = require ('node:console'); | |
console = new Console ({ // eslint-disable-line no-global-assign | |
stdout: process.stdout, stderr: process.stderr, | |
inspectOptions: { depth: Infinity, sorted: true } | |
}); | |
console.log (`Node.js ${process.version}`); | |
const __log_queueInsert__original = __log_queueInsert; | |
__log_queueInsert = function (m) { // eslint-disable-line no-func-assign | |
console.log ('[SYSTEM_LOG]: ' + m.join (' ')); | |
} | |
const __telegram_background_enqueue__seconds = 30; | |
const __telegram_background_enqueue__finalize = function () { | |
if (__telegram_background_enqueue__finalize.__intervalId) | |
clearInterval (__telegram_background_enqueue__finalize.__intervalId); | |
__telegram_background_process (); | |
} | |
const __telegram_background_enqueue__original = __telegram_background_enqueue; | |
__telegram_background_enqueue = function (...args) { // eslint-disable-line no-func-assign | |
console.log (`intercepted __telegram_background_enqueue: interval.of:${__telegram_background_enqueue__seconds}s, process.on:exit`); | |
__telegram_background_enqueue__finalize.__intervalId = setInterval (__telegram_background_process, __telegram_background_enqueue__seconds * 1000); | |
process.on ('exit', __telegram_background_enqueue__finalize); | |
__telegram_background_enqueue = __telegram_background_enqueue__original; // eslint-disable-line no-func-assign | |
return __telegram_background_enqueue__original (...args); | |
} | |
CODE:GCLOUD */ | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
/* CODE:GCLOUD | |
function system_profiling (level) { | |
if (level) { | |
const logLevel = Number (level) >= 0 && Number (level) <= 4 ? Number (level) : 3; | |
require ('@google-cloud/profiler').start ({ | |
projectId: GCLOUD_DEFAULT_CONFIG.project, logLevel, | |
serviceContext: { service: GCLOUD_DEFAULT_CONFIG.service } | |
}); | |
console.log (`NODE_PROFILING:${logLevel}`) | |
} | |
} | |
if (process.env ['NODE_PROFILING']) | |
system_profiling (process.env ['NODE_PROFILING']); | |
/* | |
CODE:GCLOUD */ | |
function system_profiling () { | |
} | |
/* CODE:GCLOUD | |
*/ | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
function adapter_test () { | |
} | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
/* CODE:GCLOUD | |
// | |
class Range { | |
constructor (sh, ad, va = undefined) { this.sh = sh; this.ad = `${sh.getName ()}!${ad}`; this.va = va; } | |
__grid () { | |
function __ref (ad) { | |
const _s = (x, a, b) => { for (var i = 0, r = ''; i < x.length; i++) if (x [i] >= a && x [i] <= b) r += x [i]; return r; } | |
const rc = ad.toUpperCase ().substring (ad.lastIndexOf ('!') + 1).split (':'); | |
const c1 = _s (rc [0], 'A', 'Z'), c2 = rc.length > 1 ? _s (rc [1], 'A', 'Z') : '', r1 = _s (rc [0], '0', '9'), r2 = rc.length > 1 ? _s (rc [1], '0', '9') : ''; | |
return [c1, r1, c2, r2]; } | |
const [c1, r1, c2, r2] = __ref (this.ad); | |
return { 'sheetId': this.sh.getId (), | |
'startRowIndex': r1 ? (Number (r1) - 1) : 0, 'endRowIndex': r2 ? Number (r2) : this.sh.getMaxRows (), | |
'startColumnIndex': c1 ? (gsheet_abc2col (c1) - 1) : 0, 'endColumnIndex': c2 ? gsheet_abc2col (c2) : this.sh.getMaxColumns (), | |
}; } | |
__a1ad (grid) { | |
return `${this.sh.getName ()}!${gsheet_col2abc (grid.startColumnIndex + 1)}${grid.startRowIndex + 1}:${gsheet_col2abc (grid.endColumnIndex)}${grid.endRowIndex}`; } | |
clear () { this.sh.sp.__request ('', `/values/${this.ad}:clear`, {}, 'POST'); return this; } | |
clearContent () { return this.clear (); } | |
getValue (valueRenderOption = 'UNFORMATTED_VALUE') { return this.getValues (valueRenderOption)?.[0]?.[0]; } | |
getValues (valueRenderOption = 'UNFORMATTED_VALUE') { | |
var v = this.va || ((this.va = this.sh.sp.__request ('', `/values/${this.ad}`, { valueRenderOption })) && (this.va = this.va.values)) || Array (); | |
const g = this.__grid (), c = (g.endColumnIndex - g.startColumnIndex), r = (g.endRowIndex - g.startRowIndex); | |
if (v.length < r) v = [...v, ...Array (r - v.length).fill (Array (c).fill (''))]; | |
for (var i = 0; i < v.length; i++) if (v [i].length < c) v [i] = [...v [i], ...Array (c - v [i].length).fill ('')]; | |
return v; } | |
setValue (va, valueInputOption = 'USER_ENTERED') { return this.setValues ([ [ va ] ], valueInputOption); } | |
setValues (va, valueInputOption = 'USER_ENTERED') { | |
for (var offset = 0, number = Math.ceil (JSON.stringify (va).length / GSHEET_CFG.PAYLOAD_SIZE_LIMIT), | |
length = Math.ceil (va.length / number), grid = this.__grid (), values, range; offset < number; offset ++) { | |
values = va.slice (offset * length, (offset + 1) * length), | |
range = this.__a1ad ({...grid, startRowIndex: grid.startRowIndex + (offset * length), endRowIndex: grid.startRowIndex + (offset * length) + values.length }); | |
this.sh.sp.__request ('', `/values/${range}`, { valueInputOption }, 'PUT', { range, values }); | |
} | |
this.va = va; return this; } | |
__rgbColor (rgbColor) { | |
const __code = (x, a) => parseInt (x.slice (a, a + 2), 16) / 256, __name = (x) => ({ 'black': '#000000' } [x]); | |
return ((rgbColor = __name (rgbColor) || rgbColor) [0] === '#') ? { red: __code (rgbColor, 1), green: __code (rgbColor, 3), blue: __code (rgbColor, 5) } : null; } | |
__numberFormat (pattern) { var type = 'NUMBER'; | |
if (pattern == '0.###############') pattern = 'General'; // type = 'NUMBER'; | |
else if (util_str_hasanychar (pattern, '%')) type = 'PERCENT'; | |
else if (util_str_hasanychar (pattern, 'ymdhMs')) type = 'DATE_TIME'; | |
return { pattern, type }; } | |
__userEnteredFormatContent (userEnteredFormat) { | |
const __fields = (x) => Object.entries (x).flatMap (([n, v]) => typeof v == 'object' && Object.keys (v).length > 0 ? Object.keys (v).map (v => n+'.'+v) : n).join (','); | |
return { 'fields': `userEnteredFormat(${__fields (userEnteredFormat)})`, 'cell': { userEnteredFormat } }; } | |
__userEnteredFormat (format) { | |
this.sh.sp.__batchUpdate ({ 'repeatCell': { ...this.__userEnteredFormatContent (format), 'range': this.__grid () } }); return this; } | |
__batchUpdateOptimizer__numberFormat (requests) { | |
const __pass = (u, xa, xb, ya, yb, c) => u.reduce ((r, u_) => { | |
if (r.length > 0 && (r [0] [xa] == u_ [xa] && r [0] [xb] == u_ [xb]) && r [0] [yb] == u_ [ya] && c (r [0].format, u_.format)) r [0] [yb] ++; else r.unshift (u_); return r; }, Array ()); | |
const __comp = (a, b) => (!a && !b) || (a && b && a == b); | |
return __pass (__pass (requests.sort ((a, b) => b.col - a.col), 'col', 'colend', 'row', 'rowend', __comp), 'row', 'rowend', 'col', 'colend', __comp); } | |
getNumberFormats () { | |
const __format = (pattern) => (pattern && pattern == 'General') ? '0.###############' : pattern; | |
const response = this.sh.sp.__request ('', ``, { 'ranges': this.ad, 'fields': 'sheets.data.rowData.values.userEnteredFormat.numberFormat' }), grid = this.__grid (); | |
return response ?.sheets ?.[0] ?.data ?.[0] ? Array.from ({ length: grid.endRowIndex - grid.startRowIndex }, (_, row) => | |
Array.from ({ length: grid.endColumnIndex - grid.startColumnIndex }, (_, col) => | |
__format (response ?.sheets ?.[0] ?.data ?.[0] ?.rowData ?.[row] ?.values ?.[col] ?.userEnteredFormat ?.numberFormat ?.pattern || '') | |
)) : undefined; | |
} | |
setNumberFormats (formats) { | |
const __cell = (grid, c, cx, r, rx) => { const cell = __DEEPCOPY (grid); cell.startColumnIndex = c + grid.startColumnIndex; cell.endColumnIndex = cx + grid.startColumnIndex; | |
cell.startRowIndex = r + grid.startRowIndex; cell.endRowIndex = rx + grid.startRowIndex; return cell; } | |
const grid = this.__grid (); | |
const requests = formats.filter ((_x1, row) => row < (grid.endRowIndex - grid.startRowIndex)).flatMap ((format_cols, row) => | |
format_cols.filter ((_x2, col) => col < (grid.endColumnIndex - grid.startColumnIndex)).map ((format, col) => ({col, colend: col + 1, row, rowend: row + 1, format}))); | |
this.sh.sp.__batchUpdate (this.__batchUpdateOptimizer__numberFormat (requests).map (r => | |
({ 'repeatCell': { ...this.__userEnteredFormatContent ({ 'numberFormat': this.__numberFormat (r.format) }), | |
'range': __cell (grid, r.col, r.colend, r.row, r.rowend) } }))); return this; } | |
getNumRows () { const grid = this.__grid (); return (grid.endRowIndex + 1) - grid.startRowIndex; } | |
setFontFamily (fontFamily) { return this.__userEnteredFormat ({ 'textFormat': { fontFamily } }); } | |
setFontSize (fontSize) { return this.__userEnteredFormat ({ 'textFormat': { fontSize } }); } | |
setFontColor (fontColor) { return this.__userEnteredFormat ({ 'textFormat': { 'foregroundColorStyle': { 'rgbColor': this.__rgbColor (fontColor) } } }); } | |
setWrapStrategy (wrapStrategy) { return this.__userEnteredFormat ({ wrapStrategy }); } | |
_setFilter (filter) { filter ['range'] = this.__grid (); this.sh.sp.__batchUpdate ({ 'setBasicFilter': { filter }}); } | |
getFilter () { return this.sh.getFilter (); } // XXX only if intersects | |
} | |
// | |
class RangeList { | |
constructor (sh, ad) { this.sh = sh; this.ad = ad.map (ad => `${this.sh.getName ()}!${ad}`); } | |
getRanges () { const va = this.sh.sp.__batchGet (this.ad); return this.ad.map ((ad, i) => new Range (this.sh, ad, va [i])); } | |
} | |
// | |
class Sheet { | |
constructor (sp, md) { this.sp = sp; this.md = md; } | |
__sync (sheetId) { this.md = this.sp.__update (sheetId); return this; } | |
__setRows (rs, re, properties, fields) { const sheetId = this.md.properties.sheetId, dimension = 'ROWS', startIndex = (rs - 1), endIndex = (re - 1); | |
this.sp.__batchUpdate ({ 'updateDimensionProperties': { 'range': { sheetId, dimension, startIndex, endIndex }, properties, fields } }); | |
return this.__sync (sheetId); } | |
activate () { return this; } | |
getIndex () { return 1; } | |
isSheetHidden () { return false; } | |
showSheet () { return this; } | |
hideSheet () { return this; } | |
getParent () { return this.sp; } | |
getId () { return this.md.properties.sheetId; } | |
getName () { return this.md.properties.title; } | |
getMaxRows () { return this.md.properties.gridProperties.rowCount; } | |
getMaxColumns () { return this.md.properties.gridProperties.columnCount; } | |
getLastRow () { return this.md.properties.gridProperties.rowCount; } // not correct really | |
getLastColumn () { return this.md.properties.gridProperties.columnCount; } // not correct really | |
getFrozenRows () { return this.md.properties.gridProperties.frozenRowCount; } | |
hideRows (rs, re) { return this.__setRows (rs, re, { 'hiddenByUser': true }, 'hiddenByUser'); } | |
showRows (rs, re) { return this.__setRows (rs, re, { 'hiddenByUser': false }, 'hiddenByUser'); } | |
appendRow () { system_error_throw ('appendRow: not implemented'); } | |
// appendRow (rv) { const sheetId = this.md.properties.sheetId, values = rv.map (stringValue => ({ 'userEnteredValue': { stringValue }})), fields = 'userEnteredValue'; | |
// this.sp.__batchUpdate ({ 'appendCells': { sheetId, 'rows': [{ values }], fields } }); return this.__sync (sheetId); } | |
deleteRows (rs, rc) { const sheetId = this.md.properties.sheetId, startRowIndex = (rs - 1), endRowIndex = (rs - 1) + rc, shiftDimension = 'ROWS'; | |
this.sp.__batchUpdate ({ 'deleteRange': { 'range' : { sheetId, startRowIndex, endRowIndex }, shiftDimension } }); return this.__sync (sheetId); } | |
insertRowsBefore (rs, rc) { const sheetId = this.md.properties.sheetId, startIndex = (rs - 1), endIndex = (rs - 1) + rc, dimension = 'ROWS'; | |
this.sp.__batchUpdate ({ 'insertDimension': { 'range': { sheetId, dimension, startIndex, endIndex }, 'inheritFromBefore': false } }); return this.__sync (sheetId); } | |
insertRowsAfter (rs, rc) { const sheetId = this.md.properties.sheetId, dimension = 'ROWS'; | |
this.sp.__batchUpdate (rs >= this.md.properties.gridProperties.rowCount ? { 'appendDimension': { sheetId, dimension, 'length': rc } } : | |
{ 'insertDimension': { 'range': { sheetId, dimension, 'startIndex': (rs - 1), 'endIndex': (rs - 1) + rc }, 'inheritFromBefore': true } }); return this.__sync (sheetId); } | |
getRange (ra, ca, nr, nc) { | |
if (typeof ra == 'string') return new Range (this, ra); | |
if (![ra, ca].every (util_str_numIs)) return undefined; | |
const { rowCount, columnCount } = this.md.properties.gridProperties, xx = (a, n, e) => (n && util_str_numIs (n)) ? a + n : e - 1; | |
return new Range (this, `${gsheet_col2abc (ca)}${ra}:${gsheet_col2abc (xx (ca, nc, columnCount))}${xx (ra, nr, rowCount)}`); } | |
getRangeList (ra) { return new RangeList (this, ra); } | |
getConditionalFormatRules () { | |
return this.md.conditionalFormats || Array (); } | |
setConditionalFormatRules (rules) { const sheetId = this.md.properties.sheetId; | |
const cur_length = (this.md.conditionalFormats || Array ()).length, new_length = rules.length, del_length = Math.max (cur_length - new_length, 0); | |
rules.forEach (rule => rule?.ranges?.forEach (range => range.sheetId = sheetId)); | |
this.sp.__batchUpdate ([ | |
...Array.from ({ length: del_length }, (_, index) => ({ 'deleteConditionalFormatRule': { sheetId, index: new_length + ((del_length - 1) - index) }})), | |
...rules.slice (0, cur_length).map ((rule, index) => ({ 'updateConditionalFormatRule': { index, rule }})), | |
...rules.slice (cur_length).map ((rule, index) => ({ 'addConditionalFormatRule': { index: cur_length + index, rule }})) | |
]); | |
this.md.conditionalFormats = rules; | |
} | |
_setFilter (filter) { this.sp.__batchUpdate ({ 'setBasicFilter': { filter }}); } | |
getFilter () { const filter = this.md.basicFilter; if (filter && filter.criteria && filter.filterSpecs) delete filter.criteria; return filter; } | |
} | |
// | |
class Spreadsheet { | |
constructor (id) { this.id = id; this.__update (); } | |
__create (sh) { return __CACHABLE (this.__create, sh.properties.sheetId, () => new Sheet (this, sh)); } | |
__update (sheetId = undefined) { this.md = this.__request (); return sheetId ? this.md.sheets.find (sh => sh.properties.sheetId == sheetId) : undefined; } | |
__request (xxxx = '', path = '', args = undefined, method = 'GET', data = undefined) { | |
return util_retry_whileNull (GSHEET_CFG.REQUEST_RETRY_COUNT, GSHEET_CFG.REQUEST_RETRY_DELAY, | |
() => util_exception_wrapper2 (() => gsheet_request (this.id, path, args, method, data), | |
(e) => { console.log ([xxxx, this.id, path, args, method]); console.log (e); return undefined; })); } | |
__batchGet (ranges, valueRenderOption = 'UNFORMATTED_VALUE') { var results = Array (); | |
for (var offset = 0, length = GSHEET_CFG.BATCH_REQUEST_LIMIT; offset < ranges.length && results; offset += length) { // could be smarter, needs to be url length | |
const re = this.__request (`${offset}/${offset + length}/${ranges.length}`, `/values:batchGet`, { 'ranges': ranges.slice (offset, offset + length), valueRenderOption }); | |
results = re && re.valueRanges ? [...results, ...re.valueRanges.map (v => v.values)] : undefined; | |
} return results; } | |
__batchUpdate (requests) { requests = util_array_always (requests); | |
const chunks = JSON.stringify (requests).length / GSHEET_CFG.PAYLOAD_SIZE_LIMIT, | |
length = Math.ceil (Math.min (requests.length / chunks, GSHEET_CFG.BATCH_UPDATE_LIMIT - GSHEET_CFG.BATCH_UPDATE_THRESHOLD)); | |
for (var offset = 0; offset < requests.length; offset += length) | |
this.__request (`${offset}/${offset + length}/${requests.length}`, `:batchUpdate`, {}, 'POST', { 'requests': requests.slice (offset, offset + length) }); } | |
getId () { return this.id; } | |
getName () { return this.md.properties.title; } | |
getSheets () { return this.md.sheets.map (sh => this.__create (sh)); } | |
getSheetByName (na) { const sh = this.md.sheets.find (sh => sh.properties && sh.properties.title == na); return sh ? this.__create (sh) : undefined; } | |
moveActiveSheet (n) { return this; } // eslint-disable-line no-unused-vars | |
duplicateActiveSheet () { system_error_throw ('duplicateActiveSheet: not supported'); } | |
} | |
// | |
class SpreadsheetApp { | |
static __create (id) { return __CACHABLE (SpreadsheetApp.__create, id, () => new Spreadsheet (id)); } | |
static openById (id) { return SpreadsheetApp.__create (id); } | |
static getActiveSpreadsheet () { return SpreadsheetApp.__create (APPLICATION_CONSOLE); } | |
} SpreadsheetApp.WrapStrategy = { 'CLIP': 'CLIP' }; | |
CODE:GCLOUD */ | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
/* CODE:GCLOUD | |
class ScriptApp { | |
static getScriptId () { return APPLICATION_SCRIPT; } | |
static getOAuthToken () { return gcloud_auth_token_header () ['Authorization'].split (' ') [1]; } | |
} | |
[ 'https://mail.google.com/', | |
'https://www.googleapis.com/auth/cloud-platform', | |
'https://www.googleapis.com/auth/devstorage.read_write', | |
'https://www.googleapis.com/auth/spreadsheets', | |
'https://www.googleapis.com/auth/script.scriptapp', | |
'https://www.googleapis.com/auth/script.projects.readonly', | |
'https://www.googleapis.com/auth/script.processes', | |
'https://www.googleapis.com/auth/script.external_request', | |
'https://www.googleapis.com/auth/drive', | |
'https://www.googleapis.com/auth/script.container.ui', | |
'https://www.googleapis.com/auth/script.deployments', | |
'https://www.googleapis.com/auth/script.metrics' | |
].forEach (scope => CLOUD_DEFAULT_AUTH_SCOPES.includes (scope) || CLOUD_DEFAULT_AUTH_SCOPES.push (scope)); | |
class PropertiesInstance { | |
constructor (type) { this._type = type; } | |
getProperty (name) { return PropertiesInstance.store [this._type] [name]; } | |
getProperties () { return PropertiesInstance.store [this._type]; } | |
setProperty (name, data) { PropertiesInstance.store [this._type] [name] = data; return this; } | |
deleteProperty (name) { delete PropertiesInstance.store [this._type] [name]; return this; } | |
deleteAllProperties () { PropertiesInstance.store [this._type] = {}; return this; } | |
getKeys () { return Object.keys (PropertiesInstance.store [this._type]); } | |
} PropertiesInstance.store = { script: {}, document: {}, user: {} }; | |
class PropertiesService { | |
static getScriptProperties () { return new PropertiesService.type ('script'); } | |
static getDocumentProperties () { return new PropertiesService.type ('document'); } | |
static getUserProperties () { return new PropertiesService.type ('user'); } | |
} PropertiesService.type = PropertiesInstance; | |
class CacheInstance { | |
constructor (type) { this._type = type; } | |
get (name) { return CacheInstance.store [this._type] [name]; } | |
getAll (names) { return names.map (name => CacheInstance.store [this._type] [name]); } | |
put (name, data, time) { CacheInstance.store [this._type] [name] = data; return this; } // eslint-disable-line no-unused-vars | |
putAll (namedatas, time) { Object.entries (namedatas).forEach (([name, data]) => CacheInstance.store [this._type] [name] = data); return this; } // eslint-disable-line no-unused-vars | |
} CacheInstance.store = { script: {} }; | |
class CacheService { | |
static getScriptCache () { return new CacheService.type ('script'); } | |
} CacheService.type = CacheInstance; | |
class Lock { | |
hasLock () { return true; } | |
releaseLock () { } | |
tryLock () { return true; } | |
waitLock () { } | |
} | |
class LockService { | |
static getScriptLock () { return new Lock (); } | |
static getDocumentLock () { return new Lock (); } | |
static getUserLock () { return new Lock (); } | |
} | |
class HtmlService { | |
} | |
class ContentService { | |
} | |
class GmailApp { | |
} | |
class Session { | |
static getScriptTimeZone () { return 'Etc/UTC'; } | |
} | |
CODE:GCLOUD */ | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
/* CODE:GCLOUD | |
function util_hash_sha256 (x) { | |
return require ('crypto').createHash ('SHA256').update (x).digest (); | |
} | |
function util_sign_rsasha256 (s, k) { | |
return require ('crypto').createSign ('RSA-SHA256').update (s).sign (k); | |
} | |
function util_base64_encode (x) { | |
return Buffer.from (x).toString ('base64'); | |
} | |
function util_base64_decode (x) { | |
return Buffer.from (x, 'base64'); | |
} | |
function util_zip (name, files) { | |
const ZipFile = require ('adm-zip'), zip = new ZipFile (); files.forEach (file => zip.addFile (file.name, file.data)); return zip.toBuffer (); | |
} | |
function util_unzip (data) { | |
const ZipFile = require ('adm-zip'), zip = new ZipFile (Buffer.from (data)); | |
return zip.getEntries ().map (entry => ({ | |
getName: () => entry.entryName, | |
getContentType: () => entry.entryName.endsWith ('txt') ? 'text/plain' : ( entry.entryName.endsWith ('csv') ? 'text/csv' : 'application/octet-stream' ), | |
getDataAsString: () => zip.readAsText (entry) | |
})); | |
} | |
function util_gzip (input) { | |
return require ('zlib').gzipSync (input); | |
} | |
function util_gunzip (input) { | |
return require ('zlib').gunzipSync (input).toString (); | |
} | |
function util_sleep (s) { | |
const waitTill = Date.now () + (s * 1000); while (waitTill > Date.now ()) { } // eslint-disable-line no-empty | |
} | |
/* | |
CODE:GCLOUD */ | |
function util_hash_sha256 (x) { | |
return Utilities.computeDigest (Utilities.DigestAlgorithm.SHA_256, x); | |
} | |
function util_sign_rsasha256 (s, k) { | |
return Utilities.computeRsaSha256Signature (s, k); | |
} | |
function util_base64_encode (x) { | |
return Utilities.base64Encode (x); | |
} | |
function util_base64_decode (x) { | |
return Utilities.base64Decode (x); | |
} | |
function util_zip (name, files) { | |
return Utilities.zip (files.map (f => Utilities.newBlob (f.data, f.type, f.name)), name).getBytes (); | |
} | |
function util_unzip (data) { | |
return Utilities.unzip (Utilities.newBlob (util_arraybuffer_to_data (data), 'application/zip')); | |
} | |
function util_gzip (input) { | |
return Utilities.gzip (Utilities.newBlob (input)).getBytes (); | |
} | |
function util_gunzip (input) { | |
return Utilities.ungzip (Utilities.newBlob (input).setContentType ('application/x-gzip')).getDataAsString (); | |
} | |
function util_sleep (m) { | |
return Utilities.sleep (m * 1000); | |
} | |
/* CODE:GCLOUD | |
*/ | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
/* CODE:GCLOUD | |
const __connect_responseDebugHeaders = (r) => r?.headers; | |
const __connect_responseDebugContent = (r) => r?.clone ()?.text (); | |
const __connect_responseFetch = (u, o) => { | |
if (o?.headers ['Content-Type'] == 'data') o.headers ['Content-Type'] = 'application/octet-stream'; | |
if (o?.headers ['Content-Type'] == 'text') o.headers ['Content-Type'] = 'text/plain'; | |
if (o.payload) o.body = o.payload, delete o.payload; | |
return sync_fetch (u, o); | |
} | |
const __connect_responseLength = (r) => r?.length || 0; | |
const __connect_responseStatus = (r) => r.status; | |
const __connect_responseCheck = (r) => r.ok || system_error_throw (`__connect_error: ${r.status} ${r.statusText}`); | |
const __connect_responseDecode = (r, t) => (t = { // eslint-disable-line no-cond-assign | |
'arraybuffer': (r) => r.arrayBuffer (), | |
'blob': (r) => r.blob (), | |
'json': (r) => r.json (), | |
'xml' : (r) => __xml_parse (r.text ()), | |
'text': (r) => String (r.text ()), | |
'data': (r) => new Uint8Array (r.arrayBuffer ()) | |
} [t]) ? t (r) : undefined; | |
function __xml_parse (text) { // eslint-disable-line no-unused-vars | |
system_error_throw ('__xml_parse: not implemented'); | |
} | |
/* | |
CODE:GCLOUD */ | |
const __connect_responseDebugHeaders = (r) => r?.getAllHeaders (); | |
const __connect_responseDebugContent = (r) => r?.getContentText (); | |
const __connect_responseFetch = (u, o) => { | |
if (o?.headers ['Content-Type'] == 'data') o.headers ['Content-Type'] = 'application/octet-stream'; | |
if (o?.headers ['Content-Type'] == 'text') o.headers ['Content-Type'] = 'text/plain'; | |
return UrlFetchApp.fetch (u, o); | |
} | |
const __connect_responseLength = (r) => r?.getContent ()?.length || 0; | |
const __connect_responseStatus = (r) => r.getResponseCode (); | |
const __connect_responseCheck = () => { } | |
const __connect_responseDecode = (r, t) => (t = { | |
'arraybuffer': (r) => util_data_to_arraybuffer (r.getBlob ().getBytes ()), | |
'blob': (r) => r.getBlob (), | |
'json': (r) => JSON.parse (r.getContentText ()), | |
'xml' : (r) => __xml_parse (r.getContentText ()), | |
'text': (r) => r.getContentText (), | |
'data': (r) => r.getContent (), | |
} [t]) ? t (r) : undefined; | |
function __xml_parse (text) { | |
return text.includes ('<') && text.includes ('>') && (text = XmlService.parse (text)) ? text?.getRootElement () : undefined; | |
} | |
/* CODE:GCLOUD | |
*/ | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
/* CODE:GLINUX | |
const __fs_cache_data = { | |
directory: process.env ['CACHEDIR'] || './cache', file: undefined, dirty: 0, flush: 25, fsize: 512, findex: 100 | |
}; | |
const __fs_cache_load = () => { if (__fs_cache_data.file) return; | |
__fs_cache_data.file = {}; | |
for (var d, i = __fs_cache_data.findex; (d = util_exception_wrapper2 (() => util_file (__fs_cache_data.directory, '/cache' + (i ++) + '.txt', 'text'))); ) | |
__fs_cache_data.file = Object.assign (__fs_cache_data.file, JSON.parse (d)); | |
debugLog (`cache: ${util_obj_length (__fs_cache_data.file)}`); | |
process.on ('exit', () => __fs_cache_save ()); | |
} | |
const __fs_cache_save = () => { if (!__fs_cache_data.file) return; | |
for (var x = Object.keys (__fs_cache_data.file), i = __fs_cache_data.findex; x.length > 0; ) { | |
var y = {}; for (var j = 0, z; j < __fs_cache_data.fsize && x.length > 0; j ++) z = x.shift (), y [z] = __fs_cache_data.file [z]; | |
util_exception_wrapper2 (() => util_file (__fs_cache_data.directory, '/cache' + (i ++) + '.txt', 'create', JSON.stringify (y))); | |
} | |
} | |
const __fs_cache_xxx = () => { if (++__fs_cache_data.dirty >= __fs_cache_data.flush) __fs_cache_data.dirty = 0, __fs_cache_save (); } | |
//const __fs_cache_del = (n) => { __fs_cache_load (); delete __fs_cache_data.file [n]; __fs_cache_xxx (); } | |
const __fs_cache_set = (n, v) => { __fs_cache_load (); __fs_cache_data.file [n] = v; __fs_cache_xxx (); } | |
const __fs_cache_get = (n) => { __fs_cache_load (); return __fs_cache_data.file?.[n]; } | |
//const __fs_cache_all = () => { __fs_cache_load (); return __fs_cache_data.file; } | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
class CacheInstance_File { | |
get (name) { return __fs_cache_get (name); } | |
put (name, data, time) { __fs_cache_set (name, data); return this; } // eslint-disable-line no-unused-vars | |
getAll (names) { return Object.fromEntries (names.map (name => [name, __fs_cache_get (name)])); } | |
putAll (namedatas, time) { Object.entries (namedatas).forEach (([name, data]) => __fs_cache_set (name, data)); return this; } // eslint-disable-line no-unused-vars | |
} CacheService.type = CacheInstance_File; | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
class PropertiesInstance_Cloud { | |
static __data (type) { | |
if (PropertiesInstance_Cloud.variables.init == false) { | |
PropertiesInstance_Cloud.variables.init = true; | |
const data = properties_cloud_request (); | |
if (data) PropertiesInstance_Cloud.variables.data = data; | |
} | |
return PropertiesInstance_Cloud.variables.data [type]; } | |
static __reset (type) { | |
PropertiesInstance_Cloud.variables.data [type] = { }; } | |
constructor (type) { this._type = type; this._data = PropertiesInstance_Cloud.__data (this._type); } | |
getProperty (name) { return this._data [name]; } | |
setProperty (name, data) { this._data [name] = data; return this; } | |
getProperties () { return this._data; } | |
deleteProperty (name) { delete this._data [name]; return this; } | |
deleteAllProperties () { PropertiesInstance_Cloud.__reset (this._type); return this; } | |
getKeys () { return Object.keys (this._data); } | |
} PropertiesInstance_Cloud.variables = { data: { script: {}, user: {}, document: {} }, init: false }; | |
PropertiesService.type = PropertiesInstance_Cloud; | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
function util_file (folder, filename, attribute, arg1) { | |
const filesystem = require ('fs'); | |
return util_exception_wrapper2 (() => { const fullname = (folder || '.') + '/' + filename; | |
if (attribute == 'modified') return filesystem.statSync (fullname) ['mtime']; | |
if (attribute == 'data' || attribute == 'arraybuffer') return filesystem.readFileSync (fullname).buffer; | |
else if (attribute == 'text') return String (filesystem.readFileSync (fullname)); | |
else if (attribute == 'delete') return filesystem.rmSync (fullname); | |
else if (attribute == 'create') return filesystem.writeFileSync (fullname, Buffer.from (arg1)); | |
return undefined; | |
}); | |
} | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
class SymbolDataStore_FileSystem extends DataStoreBase { | |
static get cacheable () { return true; } | |
static load (name, link, opts = {}) { return util_file (__fs_cache_data.directory, name, opts.type || 'text'); } | |
static save (data, name, link, opts = {}) { return util_file (__fs_cache_data.directory, name, 'create', data); } | |
} SymbolDataStore.providers.unshift (SymbolDataStore_FileSystem); | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
CODE:GLINUX */ | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
const GZip = { | |
compressToBase64: function (input) { return util_base64_encode (util_gzip (input)); }, | |
decompressFromBase64: function (input) { return util_gunzip (util_base64_decode (input)); }, | |
compressToUTF16: function (input) { return util_base32768_encode (util_gzip (input)); }, | |
decompressFromUTF16: function (input) { return util_gunzip (util_base32768_decode (input)); }, | |
compressToUint8Array : function (input) { return util_gzip (input); }, | |
decompressFromUint8Array : function (input) { return util_gunzip (input); }, | |
} | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
function properties_cloud_request () { | |
return util_exception_wrapper3 (() => connect_urlResponseJson ('Properties', APPLICATION_URL + util_str_url_args ({ properties: true }))); | |
} | |
function properties_cloud_respond () { | |
const properties = Object.fromEntries (['Script', 'Document', 'User'].map (type => [type.toLowerCase (), PropertiesService [`get${type}Properties`] ().getProperties ()])); | |
return [ JSON.stringify (properties), 'json' ]; | |
} | |
function properties_webHandler_GET (type, args) { | |
const __mimetype = (text) => ({ 'text': ContentService.MimeType.TEXT, 'json': ContentService.MimeType.JSON } [text]); | |
return connect_webHandler_process_GET (args, (parameters) => !util_is_null (parameters ['properties']), | |
() => { const [ data, type ] = properties_cloud_respond (); return data ? ContentService.createTextOutput (data).setMimeType (__mimetype (type)) : undefined; }); | |
} | |
function properties_webHandler_setup () { | |
connect_webHandler_register_GET (properties_webHandler_GET); | |
} | |
// ----------------------------------------------------------------------------------------------------------------------------------------- | |
// ----------------------------------------------------------------------------------------------------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment