Skip to content

Commit

Permalink
feat: debug mode
Browse files Browse the repository at this point in the history
  • Loading branch information
AllanChain committed Feb 11, 2024
1 parent 7815f2f commit 6a66672
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 36 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,10 @@ To remove the extension, execute:
pip uninstall jupyterlab_wakatime
```

The following content is generated with the template:

---

## Troubleshoot

If you don't see the plugin in https://wakatime.com/plugins/status, please enable `debug` setting and check both JupyterLab logs in terminal and `wakatime.log` file.

If you are seeing the frontend extension, but it is not working, check
that the server extension is enabled:

Expand All @@ -59,6 +57,10 @@ the frontend extension, check the frontend extension is installed:
jupyter labextension list
```

The following content is generated with the template:

---

## Contributing

### Development install
Expand Down
41 changes: 24 additions & 17 deletions jupyterlab_wakatime/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class BeatData(TypedDict):
filepath: str
iswrite: bool
timestamp: float
debug: bool


class BeatHandler(APIHandler):
Expand All @@ -40,27 +41,31 @@ async def post(self):
cmd_args.extend(["--time", str(data["timestamp"])])
if data["iswrite"]:
cmd_args.append("--write")
if data.get("debug"):
cmd_args.append("--verbose")
except:
self.log.info("wakatime-cli " + shlex.join(cmd_args))
return self.finish(json.dumps({"code": 400}))
self.log.info("wakatime-cli " + shlex.join(cmd_args))
if data.get("debug"):
self.log.info("wakatime-cli " + shlex.join(cmd_args))

# Async subprocess is required for non-blocking access to return code
# However, it's not supported on Windows
# As a workaround, create a Popen instance and leave it alone
if platform.system() == "Windows":
subprocess.Popen([WAKATIME_CLI, *cmd_args])
return self.finish(json.dumps({"code": 0}))

proc = await asyncio.create_subprocess_exec(
WAKATIME_CLI,
*cmd_args,
"--log-to-stdout",
"--verbose",
stdout=asyncio.subprocess.PIPE,
)
stdout, _ = await proc.communicate()
stdout = stdout.decode().strip()
if not data.get("debug"):
subprocess.Popen([WAKATIME_CLI, *cmd_args])
return self.finish(json.dumps({"code": 0}))
proc = subprocess.run([WAKATIME_CLI, *cmd_args], stdout=subprocess.PIPE)
stdout = proc.stdout.decode().strip()
else:
proc = await asyncio.create_subprocess_exec(
WAKATIME_CLI,
*cmd_args,
"--log-to-stdout",
stdout=asyncio.subprocess.PIPE,
)
stdout, _ = await proc.communicate()
stdout = stdout.decode().strip()

if proc.returncode == 112:
self.log.warning("WakaTime rate limited")
Expand All @@ -77,9 +82,11 @@ async def post(self):
for line in stdout.split("\n"):
with suppress(json.JSONDecodeError):
log = json.loads(line)
if log.get("level") != "error":
continue
self.log.error("WakaTime error: %s", log.get("message", line))
level = log.get("level", "")
if hasattr(self.log, level):
getattr(self.log, level)(
"WakaTime %s: %s", level, log.get("message")
)
return self.finish(json.dumps({"code": proc.returncode}))


Expand Down
6 changes: 6 additions & 0 deletions schema/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
"jupyter.lab.setting-icon": "jupyterlab-wakatime:wakatime",
"type": "object",
"properties": {
"debug": {
"type": "boolean",
"title": "Debug mode",
"description": "Turn on debug mode.",
"default": false
},
"status": {
"type": "boolean",
"title": "Show on status bar",
Expand Down
22 changes: 12 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { IEditorTracker } from '@jupyterlab/fileeditor'
import { ISettingRegistry } from '@jupyterlab/settingregistry'
import { IStatusBar } from '@jupyterlab/statusbar'

import { createHeart, pollStatus } from './watch'
import { Heart, pollStatus } from './watch'
import { StatusModel, WakaTimeStatus } from './status'

/**
Expand All @@ -25,44 +25,46 @@ const plugin: JupyterFrontEndPlugin<void> = {
) => {
console.log('JupyterLab extension jupyterlab-wakatime is activated!')
const statusModel = new StatusModel()
const beatHeart = createHeart(statusModel)
const heart = new Heart(statusModel)

notebooks.widgetAdded.connect((_, notebook) => {
const filepath = notebook.sessionContext.path
notebook.content.model?.contentChanged.connect(() => {
beatHeart(filepath, 'change')
heart.beat(filepath, 'change')
})
notebook.content.model?.stateChanged.connect((_, change) => {
if (change.name === 'dirty' && change.oldValue) {
beatHeart(filepath, 'write')
heart.beat(filepath, 'write')
}
})
})
notebooks.currentChanged.connect((_, notebook) => {
if (notebook === null) {
return
if (notebook !== null) {
heart.beat(notebook.sessionContext.path, 'switch')
}
beatHeart(notebook.sessionContext.path, 'switch')
})
editors.widgetAdded.connect((_, editor) => {
editor.context.fileChanged.connect(ctx => {
beatHeart(ctx.path, 'change')
heart.beat(ctx.path, 'change')
})
editor.context.saveState.connect((ctx, state) => {
if (state === 'completed') {
beatHeart(ctx.path, 'write')
heart.beat(ctx.path, 'write')
}
})
})
editors.currentChanged.connect((_, editor) => {
if (editor !== null) {
beatHeart(editor.context.path, 'switch')
heart.beat(editor.context.path, 'switch')
}
})
if (settingRegistry) {
settingRegistry
.load(plugin.id)
.then(settings => {
if (settings.get('debug').composite) {
heart.debug = true
}
if (settings.get('status').composite && statusBar) {
const wakatimeStatus = new WakaTimeStatus(statusModel)
statusBar.registerStatusItem('wakatime-status', {
Expand Down
19 changes: 14 additions & 5 deletions src/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@ export type BeatData = {
filepath: string
timestamp: number
iswrite: boolean
debug: boolean
}

export const createHeart = (statusModel: StatusModel) => {
return async (
export class Heart {
statusModel: StatusModel
debug: boolean

constructor(statusModel: StatusModel, debug: boolean = false) {
this.statusModel = statusModel
this.debug = debug
}
async beat(
filepath: string,
type: 'switch' | 'change' | 'write'
) => {
) {
console.log(type, filepath)
const now = Date.now()
if (type === 'change' && now - lastBeat < wakaInterval) {
Expand All @@ -24,14 +32,15 @@ export const createHeart = (statusModel: StatusModel) => {
const data: BeatData = {
filepath: filepath,
timestamp: now / 1e3,
iswrite: type === 'write'
iswrite: type === 'write',
debug: this.debug,
}
lastBeat = now
const { code } = await requestAPI<{ code: number }>('heartbeat', {
body: JSON.stringify(data),
method: 'POST'
})
statusModel.error = code
this.statusModel.error = code
}
}

Expand Down

0 comments on commit 6a66672

Please sign in to comment.