Browse Source

feat: recolor script-item on update error + refactor update.js

tophf 6 years ago
parent
commit
3b1fc20013
2 changed files with 93 additions and 88 deletions
  1. 78 86
      src/background/utils/update.js
  2. 15 2
      src/options/views/script-item.vue

+ 78 - 86
src/background/utils/update.js

@@ -9,100 +9,92 @@ const processes = {};
 const NO_HTTP_CACHE = {
   'Cache-Control': 'no-cache, no-store, must-revalidate',
 };
+const OPTIONS = {
+  meta: {
+    headers: { ...NO_HTTP_CACHE, Accept: 'text/x-userscript-meta' },
+  },
+  script: {
+    headers: NO_HTTP_CACHE,
+  },
+};
 
-function doCheckUpdate(script) {
-  const update = {
-    checking: true,
-  };
-  const res = {
-    cmd: CMD_SCRIPT_UPDATE,
-    data: {
-      where: {
-        id: script.props.id,
-      },
-      update,
-    },
-  };
+// resolves to true if successfully updated
+export default function checkUpdate(script) {
+  const { id } = script.props;
+  const promise = processes[id] || (processes[id] = doCheckUpdate(script));
+  return promise;
+}
+
+async function doCheckUpdate(script) {
+  const { id } = script.props;
+  try {
+    const { data: { update } } = await parseScript({
+      id,
+      code: await downloadUpdate(script),
+      update: { checking: false },
+    });
+    if (getOption('notifyUpdates')) {
+      notify({
+        title: i18n('titleScriptUpdated'),
+        body: i18n('msgScriptUpdated', [update.meta.name || i18n('labelNoName')]),
+      });
+    }
+    return true;
+  } catch (error) {
+    if (process.env.DEBUG) console.error(error);
+  } finally {
+    delete processes[id];
+  }
+}
+
+async function downloadUpdate(script) {
   const downloadURL = (
     script.custom.downloadURL
     || script.meta.downloadURL
     || script.custom.lastInstallURL
   );
-  const updateURL = script.custom.updateURL || script.meta.updateURL || downloadURL;
-  const okHandler = ({ data }) => {
-    const meta = parseMeta(data);
-    if (compareVersion(script.meta.version, meta.version) < 0) return Promise.resolve();
-    update.checking = false;
-    update.message = i18n('msgNoUpdate');
-    sendMessageOrIgnore(res);
-    return Promise.reject();
-  };
-  const errHandler = () => {
-    update.checking = false;
-    update.message = i18n('msgErrorFetchingUpdateInfo');
-    sendMessageOrIgnore(res);
-    return Promise.reject();
+  const updateURL = (
+    script.custom.updateURL
+    || script.meta.updateURL
+    || downloadURL
+  );
+  if (!updateURL) throw false;
+  let checkingMeta = true;
+  const update = {};
+  const msg = {
+    cmd: CMD_SCRIPT_UPDATE,
+    data: {
+      where: { id: script.props.id },
+      update,
+    },
   };
-  const doUpdate = () => {
-    if (!downloadURL) {
-      update.message = i18n('msgNewVersion');
-      sendMessageOrIgnore(res);
-      return Promise.reject();
+  announce(i18n('msgCheckingForUpdate'));
+  try {
+    const { data } = await request(updateURL, OPTIONS.meta);
+    const meta = parseMeta(data);
+    if (compareVersion(script.meta.version, meta.version) >= 0) {
+      announce(i18n('msgNoUpdate'), { checking: false });
+    } else if (!downloadURL) {
+      announce(i18n('msgNewVersion'), { checking: false });
+    } else {
+      announce(i18n('msgUpdating'));
+      checkingMeta = false;
+      return (await request(downloadURL, OPTIONS.script)).data;
     }
-    update.message = i18n('msgUpdating');
-    sendMessageOrIgnore(res);
-    return request(downloadURL, { headers: NO_HTTP_CACHE })
-    .then(({ data }) => data, () => {
-      update.checking = false;
-      update.message = i18n('msgErrorFetchingScript');
-      sendMessageOrIgnore(res);
-      return Promise.reject();
-    });
-  };
-  if (!updateURL) return Promise.reject();
-  update.message = i18n('msgCheckingForUpdate');
-  sendMessageOrIgnore(res);
-  return request(updateURL, {
-    headers: {
-      ...NO_HTTP_CACHE,
-      Accept: 'text/x-userscript-meta',
-    },
-  })
-  .then(okHandler, errHandler)
-  .then(doUpdate);
-}
-
-export default function checkUpdate(script) {
-  const { id } = script.props;
-  let promise = processes[id];
-  if (!promise) {
-    let updated = false;
-    promise = doCheckUpdate(script)
-    .then(code => parseScript({
-      id,
-      code,
-      update: {
-        checking: false,
-      },
-    }))
-    .then((res) => {
-      const { data: { update } } = res;
-      updated = true;
-      if (getOption('notifyUpdates')) {
-        notify({
-          title: i18n('titleScriptUpdated'),
-          body: i18n('msgScriptUpdated', [update.meta.name || i18n('labelNoName')]),
-        });
-      }
-    })
-    .catch((err) => {
-      if (process.env.DEBUG) console.error(err);
-    })
-    .then(() => {
-      delete processes[id];
-      return updated;
+  } catch (error) {
+    announce(
+      checkingMeta ? i18n('msgErrorFetchingUpdateInfo') : i18n('msgErrorFetchingScript'),
+      { error },
+    );
+  }
+  throw update.error;
+  function announce(message, { error, checking = !error } = {}) {
+    Object.assign(update, {
+      message,
+      checking,
+      // `null` is sendable in Chrome unlike `undefined`
+      error: error?.url || error || null,
     });
-    processes[id] = promise;
+    sendMessageOrIgnore(msg);
   }
-  return promise;
 }

+ 15 - 2
src/options/views/script-item.vue

@@ -1,7 +1,11 @@
 <template>
   <div
     class="script"
-    :class="{ disabled: !script.config.enabled, removed: script.config.removed }"
+    :class="{
+      disabled: !script.config.enabled,
+      removed: script.config.removed,
+      error: script.error,
+    }"
     :draggable="draggable"
     @keydownEnter="onEdit">
     <img class="script-icon hidden-xs" :src="safeIcon">
@@ -79,7 +83,7 @@
               <icon name="question"></icon>
             </a>
           </tooltip>
-          <div class="script-message" v-text="script.message"></div>
+          <div class="script-message" v-text="script.message" :title="script.error"></div>
         </div>
         <tooltip :content="i18n('buttonRemove')" align="end">
           <span class="btn-ghost" @click="onRemove">
@@ -315,6 +319,15 @@ $removedItemHeight: calc(
   &.focused {
     box-shadow: 1px 2px 9px var(--fill-8);
   }
+  &.error {
+    border-color: #f008;
+    [*|href="#refresh"] {
+      fill: #f00;
+    }
+    .script-message {
+      color: #f00a;
+    }
+  }
   &-buttons {
     line-height: 1;
     color: hsl(215, 13%, 28%);